如何修复NSBezierPath的便利初始化和闭包扩展,以使用Swift 5.0中失败的CGPath?
以下内联是我在某处获得的一种方法,用于使用方便的初始值设定项扩展如何修复NSBezierPath的便利初始化和闭包扩展,以使用Swift 5.0中失败的CGPath?,swift,macos,swift5,cgpath,nsbezierpath,Swift,Macos,Swift5,Cgpath,Nsbezierpath,以下内联是我在某处获得的一种方法,用于使用方便的初始值设定项扩展NSBezierPath,该初始值设定项将CGPath作为参数,使其行为更像iOS上的UIBezierPath 它以前可以工作,但当我尝试在Swift 5上编译它(几年后)时,我得到以下编译时错误: 捕获上下文的闭包不能形成C函数指针 我如何解决这个问题 convenience init(path : CGPath) { path.apply(info: nil, function: { (_, elementPointer
NSBezierPath
,该初始值设定项将CGPath
作为参数,使其行为更像iOS上的UIBezierPath
它以前可以工作,但当我尝试在Swift 5上编译它(几年后)时,我得到以下编译时错误:
捕获上下文的闭包不能形成C函数指针
我如何解决这个问题
convenience init(path : CGPath) {
path.apply(info: nil, function: { (_, elementPointer) in
let element = elementPointer.pointee
switch element.type {
case .moveToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 1))
self.move(to: points[0])
break
case .addLineToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 1))
self.line(to: points[0])
break
case .addQuadCurveToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 2))
let qp0 = self.currentPoint
let qp1 = points[0]
let qp2 = points[1]
let m = CGFloat(2.0 / 3.0)
var cp1 = NSPoint()
var cp2 = NSPoint()
cp1.x = (qp0.x + ((qp1.x - qp0.x) * m))
cp1.y = (qp0.y + ((qp1.y - qp0.y) * m))
cp2.x = (qp2.x + ((qp1.x - qp2.x) * m))
cp2.y = (qp2.y + ((qp1.y - qp2.y) * m))
self.curve(to: qp2, controlPoint1:cp1, controlPoint2:cp2)
case .addCurveToPoint:
let points = Array(UnsafeBufferPointer(start: element.points, count: 3))
self.curve(to:points[2], controlPoint1:points[0], controlPoint2:points[1])
break
case .closeSubpath:
self.close()
@unknown default:
break;
}
})
}
我建议使用
path.applyWithBlock
。我也会丢失所有那些不简洁的break
语句,直接访问元素.points
也许是这样的:
convenience init(path: CGPath) {
self.init()
path.applyWithBlock { elementPointer in
let element = elementPointer.pointee
switch element.type {
case .moveToPoint:
move(to: element.points[0])
case .addLineToPoint:
line(to: element.points[0])
case .addQuadCurveToPoint:
let qp0 = self.currentPoint
let qp1 = element.points[0]
let qp2 = element.points[1]
let m = CGFloat(2.0 / 3.0)
let cp1 = NSPoint(x: qp0.x + ((qp1.x - qp0.x) * m),
y: qp0.y + ((qp1.y - qp0.y) * m))
let cp2 = NSPoint(x: qp2.x + ((qp1.x - qp2.x) * m),
y: qp2.y + ((qp1.y - qp2.y) * m))
curve(to: qp2, controlPoint1: cp1, controlPoint2: cp2)
case .addCurveToPoint:
curve(to: element.points[2], controlPoint1: element.points[0], controlPoint2: element.points[1])
case .closeSubpath:
close()
@unknown default:
break
}
}
}
作为概念证明,我使用所有不同的元素类型创建了一个CGPath
,并使用上述元素类型创建了一个NSBezierPath
。然后我用它们各自的API对它们进行了笔划(深蓝色笔划中的NSBezierPath
,顶部白色笔划中的CGPath
)。这是一个快速的经验验证,转换逻辑产生了等效的路径:
这是对问题的补充“回答”。。。这是@Rob修复的问题中便利方法的补充功能,它将
NSBezierPath
转换为CGPath
。例如,这两种方法可以方便地在macOS和iOS之间进行移植,并且可以更轻松地使用NSBezierPath和其他CoreGraphics代码
private func transformToCGPath() -> CGPath {
let path = CGMutablePath()
let points = UnsafeMutablePointer<NSPoint>.allocate(capacity: 3)
let numElements = self.elementCount
if numElements > 0 {
var didClosePath = true
for index in 0..<numElements {
let pathType = self.element(at: index, associatedPoints: points)
switch pathType {
case .moveTo:
path.move(to: CGPoint(x: points[0].x, y: points[0].y))
case .lineTo:
path.addLine(to: CGPoint(x: points[0].x, y: points[0].y))
didClosePath = false
case .curveTo:
path.addCurve(to: CGPoint(x: points[0].x, y: points[0].y), control1: CGPoint(x: points[1].x, y: points[1].y), control2: CGPoint(x: points[2].x, y: points[2].y))
didClosePath = false
case .closePath:
path.closeSubpath()
didClosePath = true
@unknown default:
print("Warning! New NSBezierPath.ElementTypes() added, may affect transformToCGPath!")
}
}
if !didClosePath { path.closeSubpath() }
}
points.deallocate()
return path
}
private func transformToCGPath()->CGPath{
let path=CGMutablePath()
let points=unsafemeutablepointer.allocate(容量:3)
让numElements=self.elementCount
如果数值>0{
var didClosePath=true
对于0中的索引。我不知道您是在哪种情况下编写此代码的。假设它是NSView
的子类,我从未见过有人在其中使用闭包的情况。@Rob,我想知道。我已经开始这样做了,但我会修复它。谢谢。谢谢@Rob!我将查找此代码并尝试对其进行更多分析。您能向我解释一下闭包是什么吗ror真的很了解,applyWithBlock有多不同,为什么它会修复它?我想知道为什么原始解决方案会使用基于不安全指针的数组。你认为这与早期Swift版本的数组有关吗?看起来像CGPath。applyWithBlock()
更快速?看起来像.apply()
方法进一步推动了本机C机制,不必要地使其复杂化。因此我想我理解您的基本做法。但不太清楚编译器在抱怨什么,也不太清楚原始作者为什么使用Array()类。再次感谢!非常好。我做了大量快速但日常的工作(Linux/C/虚拟化)一直让我远离,我忘记了一些事情。对UnsafePointer的回顾很有帮助。所以我认为答案现在对我来说很清楚。节省了我很多时间,帮助我更快地戴上雨燕帽。非常感谢。应用可以追溯到OS 10.2,而应用程序WithBlock
是在10.13中引入的,毫无疑问是为了避免旧语法的局限性。显然,块到C函数的桥接随着时间的推移而不断发展。重新使用数组
,这可能是作者不熟悉使用指针的原因。从break
语句的存在来看,这些语句从来都不是必需的,这意味着有人不熟悉Sw伊芙:我不确定我是否会花太多时间去猜测原作者的理论基础。谢谢。这是一个很好的奥秘,几乎可以结束这个循环。一路上都有原始的教育经验。