如何修复 convenience init w/closure NSBezierPath 扩展以使用在 Swift 5.0 中失败的 CGPath?
How to fix convenience init w/closure Extension of NSBezierPath to use CGPath that fails in Swift 5.0?
下面的内联是我在某处获得的一种方法,用于使用以 CGPath
作为参数的便利初始值设定项来扩展 NSBezierPath
,因此它的行为更像 UIBezierPath
on [=28] =].
它以前工作过,但是当我尝试在 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
语句并直接访问 element.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
,在它上面)。这是转换逻辑产生等效路径的快速经验验证:
这是问题的补充 'answer'...它是@Rob 修复的问题中便捷方法的补充功能,它将 NSBezierPath
转换为 CGPath
.两者一起使得在 macOS 和 iOS 之间移植变得很方便,并且可以更轻松地与其他 CoreGraphics 代码一起使用 NSBezierPath。
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
}
下面的内联是我在某处获得的一种方法,用于使用以 CGPath
作为参数的便利初始值设定项来扩展 NSBezierPath
,因此它的行为更像 UIBezierPath
on [=28] =].
它以前工作过,但是当我尝试在 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
语句并直接访问 element.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
,在它上面)。这是转换逻辑产生等效路径的快速经验验证:
这是问题的补充 'answer'...它是@Rob 修复的问题中便捷方法的补充功能,它将 NSBezierPath
转换为 CGPath
.两者一起使得在 macOS 和 iOS 之间移植变得很方便,并且可以更轻松地与其他 CoreGraphics 代码一起使用 NSBezierPath。
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
}