So you want this:

Let's write an extension on UIBezierPath that creates the path outlining a single wedge.
To warm up, first we'll write a function that creates the wedge path without leaving a gap between wedges:
import UIKit
import PlaygroundSupport
// This is useful to remind us that we measure angles in radians, not degrees.
typealias Radians = CGFloat
extension UIBezierPath {
static func simonWedge(innerRadius: CGFloat, outerRadius: CGFloat, centerAngle: Radians) -> UIBezierPath {
let innerAngle: Radians = CGFloat.pi / 4
let outerAngle: Radians = CGFloat.pi / 4
let path = UIBezierPath()
path.addArc(withCenter: .zero, radius: innerRadius, startAngle: centerAngle - innerAngle, endAngle: centerAngle + innerAngle, clockwise: true)
path.addArc(withCenter: .zero, radius: outerRadius, startAngle: centerAngle + outerAngle, endAngle: centerAngle - outerAngle, clockwise: false)
path.close()
return path
}
}
With this extension, we can create wedges like this:

And we can use this extension in a UIView subclass to draw a wedge:
class SimonWedgeView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
commonInit()
}
var centerAngle: Radians = 0 { didSet { setNeedsDisplay() } }
var color: UIColor = #colorLiteral(red: 0.8549019694, green: 0.250980407, blue: 0.4784313738, alpha: 1) { didSet { setNeedsDisplay() } }
override func draw(_ rect: CGRect) {
let path = wedgePath()
color.setFill()
path.fill()
}
private func commonInit() {
contentMode = .redraw
backgroundColor = .clear
isOpaque = false
}
private func wedgePath() -> UIBezierPath {
let bounds = self.bounds
let outerRadius = min(bounds.size.width, bounds.size.height) / 2
let innerRadius = outerRadius / 2
let path = UIBezierPath.simonWedge(innerRadius: innerRadius, outerRadius: outerRadius, centerAngle: centerAngle)
path.apply(CGAffineTransform(translationX: bounds.midX, y: bounds.midY))
return path
}
}
let rootView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
rootView.backgroundColor = .white
func addWedgeView(color: UIColor, angle: Radians) {
let wedgeView = SimonWedgeView(frame: rootView.bounds)
wedgeView.color = color
wedgeView.centerAngle = angle
rootView.addSubview(wedgeView)
}
addWedgeView(color: #colorLiteral(red: 0.8549019694, green: 0.250980407, blue: 0.4784313738, alpha: 1), angle: 0)
addWedgeView(color: #colorLiteral(red: 0.5843137503, green: 0.8235294223, blue: 0.4196078479, alpha: 1), angle: 0.5 * .pi)
addWedgeView(color: #colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1), angle: .pi)
addWedgeView(color: #colorLiteral(red: 0.9686274529, green: 0.78039217, blue: 0.3450980484, alpha: 1), angle: 1.5 * .pi)
PlaygroundPage.current.liveView = rootView
Result:

So now we want to add the gaps between wedges.
Consider this diagram:

In the diagram, there's a circle of radius r (centered at the origin), and an arc of that circle that subtends angle θ. The length of the arc is θr, when θ is in radians. (This formula, θr, is why we use radians to measure angles!)
In the gapless method above, θ (as the variables innerAngle and outerAngle) was .pi / 4. But now we want the angles to be less than .pi / 4 to form a gap. We want the gap length along the inner radius to equal the gap length along the outer radius. So we have a predetermined gap length, g, and we need to compute the proper θ for it.
gapless arc length = r π / 4
gapful arc length = θ r = r π / 4 - g / 2
(We use g / 2 because each wedge has half of the gap at one end and half of the gap at the other end.)
θ r = r π / 4 - g / 2
// Solve for θ by dividing both sides by r:
θ = π / 4 - g / (2 r)
Now we can update the formulas innerAngle and outerAngle in the extension, to create paths that include a gap:
static func simonWedge(innerRadius: CGFloat, outerRadius: CGFloat, centerAngle: Radians, gap: CGFloat) -> UIBezierPath {
let innerAngle: Radians = CGFloat.pi / 4 - gap / (2 * innerRadius)
let outerAngle: Radians = CGFloat.pi / 4 - gap / (2 * outerRadius)
let path = UIBezierPath()
path.addArc(withCenter: .zero, radius: innerRadius, startAngle: centerAngle - innerAngle, endAngle: centerAngle + innerAngle, clockwise: true)
path.addArc(withCenter: .zero, radius: outerRadius, startAngle: centerAngle + outerAngle, endAngle: centerAngle - outerAngle, clockwise: false)
path.close()
return path
}
Then we update the wedgePath method of SimonWedgeView to compute and pass a gap length to the simonWidge method:
private func wedgePath() -> UIBezierPath {
let bounds = self.bounds
let outerRadius = min(bounds.size.width, bounds.size.height) / 2
let innerRadius = outerRadius / 2
let gap = (outerRadius - innerRadius) / 4
let path = UIBezierPath.simonWedge(innerRadius: innerRadius, outerRadius: outerRadius, centerAngle: centerAngle, gap: gap)
path.apply(CGAffineTransform(translationX: bounds.midX, y: bounds.midY))
return path
}
And we get the desired result:

You can find the complete playground source code (for the version with gaps) in this gist.
By the way, after you get the draw method working, you're probably going to want to detect which wedge was tapped. To do that, you'll want to override the point(inside:with:) method in SimonWedgeView. I explain what to do in this answer.