在Swift3中使用CGPattern回调时遇到问题
我试图在
Swift中使用CGPattern创建一个彩色图案. Apple在
Painting Colored Patterns的
Quartz 2D Programming Guide部分提供了一个很好的Objective-C示例.但是从Objective-C转换所有语法并不是直截了当的.另外,我想在绘图回调中使用info参数,并没有这样做的例子.
这是我的第一次尝试: class SomeShape { func createPattern() -> CGPattern? { let bounds = CGRect(x: 0,y: 0,width: someWidth,height: someHeight) let matrix = CGAffineTransform.identity var callbacks = CGPatternCallbacks(version: 0,drawPattern: nil,releaseInfo: nil) let res = CGPattern(info: nil,bounds: bounds,matrix: matrix,xStep: bounds.width,yStep: bounds.height,tiling: .noDistortion,isColored: true,callbacks: &callbacks) return res } } 显然,这需要一个适当的值来为CGPatternCallbacks的drawPattern参数,我需要将self作为info参数传递给CGPattern初始化程序. 完成此操作的正确语法是什么? 解决方法
如你所说
in your answer,CGPatternDrawPatternCallback被定义为:
typealias CGPatternDrawPatternCallback = @convention(c) (UnsafeMutableRawPointer?,CGContext) -> Void
因此,如果您想在函数中使用上下文,则需要传递自己的UnsafeMutableRawPointer?到参数 为了将self传递给此参数,可以使用 鉴于我们无法保证createPattern()的调用者将保持自我保留,我们不能将其传递给info:参数而不保留它自己.如果它是在没有保留的情况下传递的(例如使用unsafeBitCast),然后在绘制模式之前被释放 – 在尝试在绘图回调中使用悬空指针时会出现未定义的行为. 使用非托管: >您可以使用passRetained(_ :)传递引用作为1个保留的不透明指针.toOpaque() 例如: class SomeShape { // the bounds of the shape to draw let bounds = CGRect(x: 0,width: 40,height: 40) func createPattern() -> CGPattern? { var callbacks = CGPatternCallbacks(version: 0,drawPattern: { info,ctx in // cast the opaque pointer back to a SomeShape reference. let shape = Unmanaged<SomeShape>.fromOpaque(info!).takeUnretainedValue() // The code to draw a single tile of the pattern into "ctx"... // (in this case,two vertical strips) ctx.saveGState() ctx.setFillColor(UIColor.red.cgColor) ctx.fill(CGRect(x: 0,width: shape.bounds.width / 2,height: shape.bounds.height)) ctx.setFillColor(UIColor.blue.cgColor) ctx.fill(CGRect(x: 20,height: shape.bounds.height)) ctx.restoreGState() },releaseInfo: { info in // when the CGPattern is freed,release the info reference,// consuming the +1 retain when we originally passed it to the CGPattern. Unmanaged<SomeShape>.fromOpaque(info!).release() }) // retain self before passing it off to the info: parameter as an opaque pointer. let unsafeSelf = Unmanaged.passRetained(self).toOpaque() return CGPattern(info: unsafeSelf,matrix: .identity,callbacks: &callbacks) } } 或者,如果你想要SomeShape的值语义,你可以使它成为一个结构更好的解决方案.然后在创建模式时,您可以将它包装在Context堆分配的框中,然后再将其传递给info:参数: struct SomeShape { // the bounds of the shape to draw let bounds = CGRect(x: 0,height: 40) func createPattern() -> CGPattern? { final class Context { let shape: SomeShape init(_ shape: SomeShape) { self.shape = shape } } var callbacks = CGPatternCallbacks(version: 0,ctx in // cast the opaque pointer back to a Context reference,// and get the wrapped shape instance. let shape = Unmanaged<Context>.fromOpaque(info!).takeUnretainedValue().shape // ... },// consuming the +1 retain when we originally passed it to the CGPattern. Unmanaged<Context>.fromOpaque(info!).release() }) // wrap self in our Context box before passing it off to the info: parameter as a // +1 retained opaque pointer. let unsafeSelf = Unmanaged.passRetained(Context(self)).toOpaque() return CGPattern(info: unsafeSelf,callbacks: &callbacks) } } 现在这也考虑了任何保留周期问题. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |