2017-06-07 3 views
2

En traitant une API objC, je reçois un NSDictionary<NSString *, id> *> qui se traduit par [String : Any] dans Swift et que j'utilisais pour NSAttributedString.addAttributes:range:.Comment faire pour convertir [String: Any] à [NSAttributedStringKey: Any]

Cependant, cette signature de méthode a maintenant été modifiée avec Xcode 9 et nécessite maintenant un [NSAttributedStringKey : Any].

let attr: [String : Any]? = OldPodModule.getMyAttributes() 
// Cannot assign value of type '[String : Any]?' to type '[NSAttributedStringKey : Any]?' 
let newAttr: [NSAttributedStringKey : Any]? = attr 
if let newAttr = newAttr { 
    myAttributedString.addAttributes(newAttr, range: range) 
} 

Comment convertir un [String : Any] à un [NSAttributedStringKey : Any]?

Répondre

10

NSAttributedStringKey a an initialiser that takes a String, et vous pouvez utiliser init(uniqueKeysWithValues:) initialiseur de Dictionary afin de construire un dictionnaire à partir d'une séquence de tuples clé-valeur où chaque clé est unique (comme est le cas ici).

Nous avons juste besoin d'appliquer une transformation à attr qui convertit chaque touche String en un NSAttributedStringKey avant d'appeler initialiseur de Dictionary.

Par exemple:

let attributes: [String : Any]? = // ... 

let attributedString = NSMutableAttributedString(string: "hello world") 
let range = NSRange(location: 0, length: attributedString.string.utf16.count) 

if let attributes = attributes { 
    let convertedAttributes = Dictionary(uniqueKeysWithValues: 
     attributes.lazy.map { (NSAttributedStringKey($0.key), $0.value) } 
    ) 
    attributedString.addAttributes(convertedAttributes, range: range) 
} 

Nous utilisons lazy ici pour éviter la création d'un réseau intermédiaire inutile.

+2

Merci! Pour être exhaustif, je devais aussi faire l'opération inverse ('[NSAttributedStringKey: Any]' à '[String: Any]') et dans ce cas c'était 'Dictionary (uniqueKeysWithValues: attr.lazy.map {($ 0). key.rawValue, $ 0.value)}) '. –

+0

@Hamish Pourquoi «paresseux»? Est-ce que 'attr.map {/ * ... * /}' ne ferait pas la même chose dans ce cas? –

+1

@MatusalemMarques On obtiendrait le même résultat, mais l'utilisation de lazy évite la création d'un tableau intermédiaire inutile (les paires clé-valeur ne sont répétées qu'une fois et insérées dans le nouveau dictionnaire, avec la transformation donnée appliquée). – Hamish

0

Vous pouvez utiliser le

`NSAttributedStringKey(rawValue: String)` 

initialiseur. Mais, avec cela, il va créer un objet même si la chaîne attribuée ne sera pas affectée. Par exemple,

`NSAttributedStringKey(rawValue: fakeAttribute)` 

va encore créer une clé pour le dictionnaire. En outre, ceci est seulement disponible dans iOS 11 donc utilisez avec prudence pour la rétrocompatibilité.