0

CATextLayer.font property is an opaque CFTypeRef. Is there a way of converting that reference to a UIFont? I don't mind if it returns an optional UIFont.

David James
  • 2,430
  • 1
  • 26
  • 35
  • 1
    It's `May be either a CTFont, a CGFont, an instance of NSFont (macOS only), or a string naming the font` according to the doc. So https://stackoverflow.com/questions/6714858/iphone-convert-ctfont-to-uifont, https://stackoverflow.com/questions/9205709/how-to-convert-cgfontref-to-uifont etc.? Depending on the type, function equivalent name should be available in Swift. https://stackoverflow.com/questions/3471964/determining-what-a-cftyperef-is to get the type? – Larme Dec 21 '17 at 10:32
  • Since you created the text layer and configured it, how can you not know what font you assigned it? – matt Dec 21 '17 at 17:04
  • Easy. This is part of a general framework, and I use text layers in several places, with different fonts. In fact, my answer below is a modified version of a protocol implementation that requires a `get` and a `set`. No assumptions are made. – David James Dec 21 '17 at 17:19

2 Answers2

2

I just wrote the following extension which should handle: CTFont, CGFont, string name or UIFont:

extension CATextLayer {
    public var typeFace:UIFont? {
        let name:String
        switch font {
        case let ctFont as CTFont :
            // If you assign a UIFont to CATextLayer.font
            // it is implicitly converted to CTFont,
            // so this case will be called.
            guard let _name = CTFontCopyName(ctFont, kCTFontPostScriptNameKey) else {
                return nil
            }
            name = _name as NSString as String
        case let cgFont as CGFont :
            guard let _name = cgFont.postScriptName else {
                return nil
            }
            name = _name as NSString as String
        case let string as NSString :
            name = string as String
        case let string as String :
            name = string
        default:
            return nil
        }
        return UIFont(name:name, size:fontSize)
    }
}

On a side note, I found this comment in docs inaccurate:

In iOS, you cannot assign a UIFont object to this property.

From my tests I was able to set a UIFont on CATextLayer.font and it appears to work fine.


EDIT

It turns out when you assign a UIFont to CATextLayer.font it is converted to a CTFont behind the scenes, so in order to get the UIFont back out it's necessary to convert from CTFont to UIFont (which my code does). Simply casting to UIFont would not work.

David James
  • 2,430
  • 1
  • 26
  • 35
0

You can do like this,

let font : UIFont = layer.font as! UIFont

Hope this helps

Hitesh Sultaniya
  • 929
  • 1
  • 7
  • 12
  • This is OK only a UIFont is assigned in the first place, in any other case it will fail. On a side note, I would not force cast, since my return type is `UIFont?` it can just `return self.font as? UIFont`. – David James Dec 21 '17 at 11:25