Swift 4 Ошибка преобразования - NSAttributedStringKey: Любой

Недавно я конвертировал свое приложение, и я продолжаю получать сообщение об ошибке

"Невозможно преобразовать значение типа '[String: Any]' в ожидаемый тип аргумента '[NSAttributedStringKey: Any]?'

barButtonItem.setTitleTextAttributes(attributes, for: .normal)

Весь код:

 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
}

Ответ 1

Почему вы получили эту ошибку

Ранее ваши attributes определялись как [String: Any], где ключ берется из NSAttributedStringKey в виде строки или NSAttributedString.Key в Swift 4.2.

Во время миграции компилятор пытается сохранить тип [String: Any]. Однако NSAttributedStringKey становится структурой в swift 4. Таким образом, компилятор пытается изменить это на строку, получая ее необработанное значение.

В этом случае setTitleTextAttributes ищет [NSAttributedStringKey: Any] но вы [NSAttributedStringKey: Any] [String: Any]

Чтобы исправить эту ошибку:

Удалите .rawValue и .rawValue ваши attributes как [NSAttributedStringKey: Any]

А именно, измените следующую строку

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

в

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

И в Swift 4.2,

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

Ответ 2

Ожидается NSAttributedStringKey (NSAttributedStringKey.font) и вы отправляете String (NSAttributedStringKey.font.rawValue).

Итак, замените NSAttributedStringKey.font.rawValue на NSAttributedStringKey.font, как показано ниже:

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

Ответ 3

Как отмечалось в предыдущих ответах, NSAttributedStringKey был изменен на структуру в Swift 4. Однако другие объекты, которые используют NSAttributedStringKey, по-видимому, не обновлялись одновременно.

Самое простое исправление без изменения какого-либо другого кода - это добавить .rawValue ко всем входящим в набор NSAttributedStringKey сеттерам - превратить имена ключей в String s:

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

Обратите внимание, что теперь вам не понадобится ! в as.

В качестве альтернативы вы можете пропустить приведение as в конце, объявив массив [String : Any] upfront:

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

Конечно, вам нужно добавить .rawValue для каждого элемента NSAttributedStringKey, который вы установили.

Ответ 4

Линейный ответ верен для случаев, когда вам все еще нужно использовать [String: Any] а не [NSAttributedStringKey: Any].

Например, в UIKit UITextView.typingAttributes по-прежнему имеет тип [String: Any]. Таким образом, для этого свойства вы должны использовать преобразованные атрибуты (включая пользовательские):

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

где toTypingAttributes() - это функция, определяемая расширением в любом из ваших файлов проекта:

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

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

        return convertedDictionary
}