Search code examples
iosswiftcore-text

How to create CTRunDelegate in Swift 2.0


I am using CoreText to handle NSTextAttachment. CoreText need a CTRunDelegate to layout the attachment. But I got error when running the following code.

class RunDelegate: NSObject {
    let image: UIImage
    let font: UIFont

    init(image: UIImage, font: UIFont) {
        self.image = image
        self.font = font
    }
}

private func generateRunDelegate(attachment: NSTextAttachment, font: UIFont) -> CTRunDelegateRef {
    var d = RunDelegate(image: attachment.image!, font: font)
    var cbs = CTRunDelegateCallbacks(version: kCTRunDelegateCurrentVersion, dealloc: { (p) -> Void in

        }, getAscent: { (p) -> CGFloat in
            let d = UnsafeMutablePointer<RunDelegate>(p).memory
            return d.image.size.height + d.font.descender // Error here, EXC_BAD_ACCESS(code = 1)
        }, getDescent: { (p) -> CGFloat in
            let d = UnsafeMutablePointer<RunDelegate>(p).memory
            return -d.font.descender
        }) { (p) -> CGFloat in
            let d = UnsafeMutablePointer<RunDelegate>(p).memory
            return d.image.size.width
    }
    return CTRunDelegateCreate(&cbs, &d)!
}

Can someone help? Thanks!


Solution

  • Please try this code.

    class RunDelegate: NSObject {
        let image: UIImage
        let font: UIFont
    
        class func object(pointer: UnsafeMutablePointer<Void>) -> RunDelegate {
            return Unmanaged<RunDelegate>.fromOpaque(COpaquePointer(pointer)).takeRetainedValue()
        }
    
        init(image: UIImage, font: UIFont) {
            self.image = image
            self.font = font
        }
    }
    
    private func generateRunDelegate(attachment: NSTextAttachment, font: UIFont) -> CTRunDelegateRef {
        var d = RunDelegate(image: attachment.image!, font: font)
        var cbs = CTRunDelegateCallbacks(version: kCTRunDelegateCurrentVersion,
               dealloc: { (p) -> Void in
    
            }, getAscent: { (p) -> CGFloat in
                let d = RunDelegate.object(pointer: p)
                return d.image.size.height + d.font.descender
            }, getDescent: { (p) -> CGFloat in
                let d = RunDelegate.object(pointer: p)
                return -d.font.descender
            }) { (p) -> CGFloat in
                let d = RunDelegate.object(pointer: p)
                return d.image.size.width
        }
        return CTRunDelegateCreate(&cbs, d)!
    }
    

    I thought it is not correctly generated UnsafePointer.