noname
noname

Reputation: 127

Get font attributes in swift 4

I've migrated project from swift 3 to swift 4 and cannot find a info how to get a font attribute from a UIFontDescriptor. Here is the code which works perfect in swift 3 :

 @objc convenience init(myCoder aDecoder: NSCoder) {
        if let fontDescriptor = aDecoder.decodeObject(forKey: "UIFontDescriptor") as? UIFontDescriptor {
            if let fontAttribute = fontDescriptor.fontAttributes["NSCTFontUIUsageAttribute"] as? String {
                var fontName = ""
                switch fontAttribute {
                case "CTFontRegularUsage":
                    fontName = Roboto.regular.rawValue
                case "CTFontEmphasizedUsage", "CTFontBoldUsage":
                    fontName = Roboto.bold.rawValue
                default:
                    fontName = Roboto.regular.rawValue
                }
                self.init(name: fontName, size: fontDescriptor.pointSize)!
            }
            else {
                self.init(myCoder: aDecoder)
            }
        }
        else {
            self.init(myCoder: aDecoder)
        }
    }

But In swift 4 the line :

if let fontAttribute = fontDescriptor.fontAttributes["NSCTFontUIUsageAttribute"] as? String

has an error : Ambiguous reference to member 'subscript'. Any ideas how can I change it ?

Thanks!

Upvotes: 3

Views: 4147

Answers (5)

Javi AP
Javi AP

Reputation: 452

This work for me, creating a static value nsctFontUIUsage for NSCTFontUIUsageAttribute to then use it in fontDescriptor.fontAttributes[.nsctFontUIUsage]:

extension UIFontDescriptor.AttributeName {
    static let nsctFontUIUsage = UIFontDescriptor.AttributeName(rawValue: "NSCTFontUIUsageAttribute")
}

extension UIFont {
    @objc convenience init(myCoder aDecoder: NSCoder) {
        guard
            let fontDescriptor = aDecoder.decodeObject(forKey: "UIFontDescriptor") as? UIFontDescriptor,
            let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String else {
                self.init(myCoder: aDecoder)
                return
        }
        var fontName = ""
        switch fontAttribute {

        case "CTFontRegularUsage":
            fontName = Resources.Fonts.Weight.regular

        case "CTFontEmphasizedUsage", "CTFontBoldUsage":
            fontName = Resources.Fonts.Weight.semibold

        case "CTFontObliqueUsage":
            fontName = Resources.Fonts.Weight.italic

        default:
            fontName = Resources.Fonts.Weight.light
        }
        self.init(name: fontName, size: fontDescriptor.pointSize)!
    }
}

Upvotes: 2

dferrero
dferrero

Reputation: 467

1) Be sure all your Project / Target Build Settings show Swift Language Version 4.x (4.0 for now). Without this set, the new UIFontDescriptor values won't be available. Note: a project with multiple targets may misbehave depending on which target you have selected and the Swift version specified for that target. To avoid, be sure all targets are updated to Swift 4.0.

2) Access a specific UIFontAttribute using the built in static types, paying attention to the expected return types.

For a UIFontAttribute with an optional NSString return type:

let fontAttribute = fontDescriptor.object(forKey: .face) as? String

or in your example, where no built-in static types exist:

let fontAttribute = fontDescriptor.object(forKey: UIFontDescriptor.AttributeName(rawValue: "NSCTFontUIUsageAttribute")) as? String

Upvotes: 1

吳政緯
吳政緯

Reputation: 1

Here is my Solution. Work for me

 @objc convenience init(myCoder aDecoder: NSCoder) {
    if let fontDescriptor = aDecoder.decodeObject(forKey: "UIFontDescriptor") as? UIFontDescriptor {

           let fontAttribute = UIFontDescriptor.AttributeName("NSCTFontUIUsageAttribute")  
        if let fontAttribute = fontDescriptor.fontAttributes[fontAttribute] as? String {

           var fontName = ""
            switch fontAttribute {
            case "CTFontRegularUsage":
                fontName = Roboto.regular.rawValue
            case "CTFontEmphasizedUsage", "CTFontBoldUsage":
                fontName = Roboto.bold.rawValue
            default:
                fontName = Roboto.regular.rawValue
            }
            self.init(name: fontName, size: fontDescriptor.pointSize)!
        }
        else {
            self.init(myCoder: aDecoder)
        }
    }
    else {
        self.init(myCoder: aDecoder)
    }
}

Upvotes: 0

matt
matt

Reputation: 535231

It looks like you're trying to treat your custom font as a dynamic type font. The supported way to do that in iOS 11 is to use UIFontMetrics.

Upvotes: 1

Daniel
Daniel

Reputation: 9040

let font: UIFont

let fontAttribute = UIFontDescriptor.AttributeName("NSCTFontUIUsageAttribute")

let fontUsageAttribute = font.fontDescriptor.fontAttributes[fontAttribute] as? String

Upvotes: 2

Related Questions