web-dev-qa-db-fra.com

Comment convertir un NSDictionary en un dictionnaire Swift <String, NSObject>?

Je suis en train de réécrire un cours Objective-C à Swift pour avoir une idée de la langue. En Objective-C, ma classe comprenait la méthode suivante:

- (id) initWithCoder:(NSCoder *)aDecoder
{
    return [self initWithActionName:[aDecoder decodeObjectOfClass:[NSString class] forKey:@"actionName"]
                            payload:[aDecoder decodeObjectOfClass:[NSDictionary class] forKey:@"payload"]
                          timestamp:[aDecoder decodeObjectOfClass:[NSDate class] forKey:@"timestamp"]];
}

Après quelques essais et erreurs avec le compilateur, j'ai réussi à le réécrire comme ceci:

convenience init(aDecoder: NSCoder) {
    let actionName = aDecoder.decodeObjectOfClass(NSString.self, forKey: "actionName") as NSString
    let payload = aDecoder.decodeObjectOfClass(NSDictionary.self, forKey: "payload") as NSDictionary
    let timestamp = aDecoder.decodeObjectOfClass(NSDate.self, forKey: "timestamp") as NSDate
    self.init(actionName: actionName, payload: payload, timestamp: timestamp)
}

Cependant, cela me donne toujours une erreur sur la dernière ligne: «Impossible de trouver une surcharge pour init qui accepte les arguments fournis.» La signature de méthode de init est

init(actionName: String, payload: Dictionary<String, NSObject>, timestamp: NSDate)

donc je suppose que le problème est que j'essaie de passer une NSDictionary au lieu d'un Dictionary<String, NSObject>. Comment puis-je convertir entre ces deux types pas assez équivalents? Devrais-je simplement utiliser NSDictionary pour tout le code devant interagir avec d'autres composants Objective-C?

19
bdesham

Décodez votre dictionnaire en tant que Dictionary<String, NSObject> au lieu de NSDictionary.

let payload = aDecoder.decodeObjectOfClass(NSDictionary.self, forKey: "payload") as! Dictionary<String, NSObject>

Étant donné que vous utilisez Cocoa Touch pour la sérialisation et la désérialisation, elles sont numérotées en tant que NSDictionary, mais vous pouvez le convertir en un Swift Dictionary<,>, conformément à WWDC 2014 Intermédiaire Swift et Advanced Swift videos.

Vous pouvez également décoder en tant que NSDictionary, puis convertir explicitement l'objet de la manière suivante:

self.init(actionName: actionName, payload: payload as! Dictionary<String, NSObject>, timestamp: timestamp)

Fondamentalement, vous jouez ici avec covariance/contravariance.

14
Leo Natan

Etes-vous sûr que c'est la déclaration correcte pour init? L'ordre des arguments est différent de celui que vous appelez dans votre code Objective-C.

Donc, si vous voulez une réimplémentation précise, le dernier appel devrait probablement être self.init(actionName: actionName, timestamp: timestamp, payload: payload). Appeler l'initialiseur avec le mauvais ordre d'arguments entraînerait exactement le message d'erreur que vous obtenez.

1
Lukas