In the pre-release documentation there appears to be no Swift version of CGPathApply. Is there an equivalent or alternative? I\'m trying to get all subpaths of a CGPath so t
(Hint: if you have to support an iOS before iOS 11, use the accepted answer. If you can require iOS 11, this answer is much easier.)
Since iOS 11, there is an official answer from Apple to this question: CGPath.applyWithBlock(_:)
.
This makes all the dirty tricks unnecessary that come from the problem that CGPath.apply(info:function:)
is a C function that does not allow information transported in and out of the function in a usual swifty way.
The following code allows you to do:
let pathElements = path.pathElements()
To be able to do that, copy & paste
import CoreGraphics
extension CGPath {
func pathElements() -> [PathElement] {
var result = [PathElement]()
self.applyWithBlock { (elementPointer) in
let element = elementPointer.pointee
switch element.type {
case .moveToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 1))
let el = PathElement.moveToPoint(points[0])
result.append(el)
case .addLineToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 1))
let el = PathElement.addLineToPoint(points[0])
result.append(el)
case .addQuadCurveToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 2))
let el = PathElement.addQuadCurveToPoint(points[0], points[1])
result.append(el)
case .addCurveToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 3))
let el = PathElement.addCurveToPoint(points[0], points[1], points[2])
result.append(el)
case .closeSubpath:
result.append(.closeSubpath)
@unknown default:
fatalError()
}
}
return result
}
}
public enum PathElement {
case moveToPoint(CGPoint)
case addLineToPoint(CGPoint)
case addQuadCurveToPoint(CGPoint, CGPoint)
case addCurveToPoint(CGPoint, CGPoint, CGPoint)
case closeSubpath
}
or take this code as an example to how to use CGPath.applyWithBlock(_:)
yourself.
For completeness, this is the official documentation from Apple: https://developer.apple.com/documentation/coregraphics/cgpath/2873218-applywithblock
Since iOS 13 there is an even more elegant official answer from Apple: Use SwiftUI
(even if your UI isn't in SwiftUI
)
Transform your cgPath
into a SwiftUI Path
let cgPath = CGPath(ellipseIn: rect, transform: nil)
let path = Path(cgPath)
path.forEach { element in
switch element {
case .move(let to):
break
case .line(let to):
break
case .quadCurve(let to, let control):
break
case .curve(let to, let control1, let control2):
break
case .closeSubpath:
break
}
}
Variable element
is of type Path.Element which is a pure Swift Enum, so there aren't even tricks necessary to get the values out of element.
For completeness, this is th official Apple documentation: https://developer.apple.com/documentation/swiftui/path/3059547-foreach