Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift 4 Conversion error - NSAttributedStringKey: Any

Tags:

swift4

I converted my app recently and I keep getting the error

"Cannot convert value of type '[String : Any]' to expected argument type '[NSAttributedStringKey: Any]?'

barButtonItem.setTitleTextAttributes(attributes, for: .normal)

Whole code:

 class func getBarButtonItem(title:String) -> UIBarButtonItem {
    let barButtonItem = UIBarButtonItem.init(title: title, style: .plain, target: nil, action: nil)
    let attributes = [NSAttributedStringKey.font.rawValue:  UIFont(name: "Helvetica-Bold", size: 15.0)!, NSAttributedStringKey.foregroundColor: UIColor.white] as! [String : Any]
    barButtonItem.setTitleTextAttributes(attributes, for: .normal)

    return barButtonItem
}
like image 471
Eazy Avatar asked Sep 20 '17 06:09

Eazy


4 Answers

Why you got this error

Previously, your attributes is defined as [String: Any], where the key comes from NSAttributedStringKey as a string or NSAttributedString.Key in Swift 4.2

During the migration, the compiler tries to keep the [String: Any] type. However, NSAttributedStringKey becomes a struct in swift 4. So the compiler tries to change that to string by getting its raw value.

In this case, setTitleTextAttributes is looking for [NSAttributedStringKey: Any] but you provided [String: Any]

To fix this error:

Remove .rawValue and cast your attributes as [NSAttributedStringKey: Any]

Namely, change this following line

let attributes = [NSAttributedStringKey.font.rawValue:
    UIFont(name: "Helvetica-Bold", size: 15.0)!, 
    NSAttributedStringKey.foregroundColor: UIColor.white] as! [String : Any]

to

let attributes = [NSAttributedStringKey.font:
    UIFont(name: "Helvetica-Bold", size: 15.0)!, 
    NSAttributedStringKey.foregroundColor: UIColor.white] as! [NSAttributedStringKey: Any]

And in Swift 4.2,

 let attributes = [NSAttributedString.Key.font:
    UIFont(name: "Helvetica-Bold", size: 15.0)!, 
    NSAttributedString.Key.foregroundColor: UIColor.white] as! [NSAttributedStringKey: Any]
like image 76
Fangming Avatar answered Nov 12 '22 22:11

Fangming


Its expecting NSAttributedStringKey(NSAttributedStringKey.font) and you are sending String(NSAttributedStringKey.font.rawValue).

So please replace NSAttributedStringKey.font.rawValue with NSAttributedStringKey.font like below :

let attributes = [NSAttributedStringKey.font:  UIFont(name: "Helvetica-Bold", size: 15.0)!, NSAttributedStringKey.foregroundColor: UIColor.white]
like image 40
Vini App Avatar answered Nov 12 '22 21:11

Vini App


As noted in previous answers, NSAttributedStringKey was changed to a struct in Swift 4. However, other objects that use NSAttributedStringKey apparently didn't get updated at the same time.

The easiest fix, without having to change any of your other code, is to append .rawValue to all your occurrences of NSAttributedStringKey setters - turning the key names into Strings:

let attributes = [
    NSAttributedStringKey.font.rawValue:  UIFont(name: "Helvetica-Bold", size: 15.0)!,
    NSAttributedStringKey.foregroundColor.rawValue: UIColor.white
] as [String : Any]

Note that you won't need the ! at the as now, either.

Alternatively, you can skip the as cast at the end by declaring the array to be [String : Any] upfront:

let attributes: [String : Any] = [
    NSAttributedStringKey.font.rawValue:  UIFont(name: "Helvetica-Bold", size: 15.0)!,
    NSAttributedStringKey.foregroundColor.rawValue: UIColor.white
]

Of course, you still need to append the .rawValue for each NSAttributedStringKey item you set.

like image 5
leanne Avatar answered Nov 12 '22 21:11

leanne


leanne's answer is correct for the cases where you still need to use [String : Any] and not [NSAttributedStringKey : Any].

For example, in UIKit UITextView.typingAttributes is still of type [String : Any]. So for that property you have to use converted attributes (including custom ones):

let customAttributeName = "MyCustomAttributeName"
let customValue: CGFloat = 15.0

let normalTextAttributes: [NSAttributedStringKey : Any] =
            [NSAttributedStringKey.font : UIFont.systemFont(ofSize: 14.0),
             NSAttributedStringKey.foregroundColor : UIColor.blue,
             NSAttributedStringKey.backgroundColor : UIColor.clear,
             NSAttributedStringKey(rawValue: customAttributeName): customValue]

textView.typingAttributes = normalTextAttributes.toTypingAttributes()

where toTypingAttributes() is a function defined by extension in any of your project files:

extension Dictionary where Key == NSAttributedStringKey {
    func toTypingAttributes() -> [String: Any] {
        var convertedDictionary = [String: Any]()

        for (key, value) in self {
            convertedDictionary[key.rawValue] = value
        }

        return convertedDictionary
}
like image 3
roxanneM Avatar answered Nov 12 '22 22:11

roxanneM