Swift   发布时间:2022-04-30  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了在Swift3中使用CGPattern回调时遇到问题大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我试图在 Swift中使用CGPattern创建一个彩色图案. Apple在 Painting Colored PatternsQuartz 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

@convention(c)属性(仅显示生成标题中)表示所使用的函数值必须与C兼容,因此无法捕获任何上下文(因为C函数只不过是函数的原始指针,并且不要不存储额外的上下文对象).

因此,如果您想在函数中使用上下文,则需要传递自己的UnsafeMutableRawPointer?到参数CGPattern‘s initialiser.这将被调用时作为给定绘图模式函数的第一个参数传递.

为了将self传递给此参数,可以使用Unmanaged.这允许您在引用和不透明指针之间进行转换,并且与unsafeBitCast不同,还允许您在执行此操作时控制引用的内存管理.

鉴于我们无法保证createPattern()的调用者将保持自我保留,我们不能将其传递给info:参数而不保留它自己.如果它是在没有保留的情况下传递的(例如使用unsafeBitCast),然后在绘制模式之前被释放 – 在尝试在绘图回调中使用悬空指针时会出现未定义的行为.

使用非托管:

>您可以使用passRetained(_ :)传递引用作为1个保留的不透明指针.toOpaque()
>您可以使用fromOpaque(_ :)获取此指针的引用.takeUnretainedValue()(实例将保留)
>然后,您可以使用fromOpaque(_ :).release()来使用1 retain.在释放CGPattern时,您将要执行此操作.

例如:

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)
    }
}

在这虑了任何保留周期问题.

大佬总结

以上是大佬教程为你收集整理的在Swift3中使用CGPattern回调时遇到问题全部内容,希望文章能够帮你解决在Swift3中使用CGPattern回调时遇到问题所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。