J'écris une extension pour combler les valeurs du dictionnaire entre FirebaseDatabase et Eureka .
private extension Dictionary {
func firebaseFriendlyDictionary() -> [String: Any?] {
return self.map({ (key: String, value: Any?) -> (String, Any?) in
if value is NSDate {
return (key, (value as! NSDate).timeIntervalSince1970)
}
return (key, value)
})
}
}
Mais je reçois cette erreur lorsque j'essaye de construire:
map produces '[T]', not the expected contextual result type '[String: Any?]'
Votre problème réside dans le fait que map
renvoie toujours un Array
, même lorsqu'il est appliqué sur un Dictionary
. Votre message d'erreur signifie essentiellement que vous avez déclaré votre méthode comme renvoyant un Dicitonary
, mais l'instruction à l'intérieur renvoie un Array
([T]
- signifie un tableau avec des objets de certains type T). Dans votre cas, le tableau retourné par map
contiendra tuples (en savoir plus ici ). Dans ce cas, il ressemble à une paire clé-valeur, mais ce n'est pas équivalent à une paire clé-valeur à l'intérieur d'un dictionnaire. Fondamentalement, les tuples vous permettent de renvoyer plusieurs valeurs/objets à partir de la méthode. Vous pouvez les considérer comme des structures anonymes .
À mon avis, il n'est pas nécessaire d'utiliser un map
pour accomplir ce dont vous avez besoin - la solution fournie par M. Xcoder est la voie à suivre.
Si vous voulez vraiment utiliser quelque chose de fonctionnel comme map
, la méthode que vous voulez réellement est reduce
.
Je vais démontrer. Pour que les choses soient aussi claires que possible, je pense que cela aidera si nous séparons la transformation à laquelle vos valeurs sont soumises en fonction propre:
func dateToSeconds(_ thing:Any?) -> Any? {
guard let date = thing as? Date else {return thing}
return date.timeIntervalSince1970
}
D'accord, voici donc notre dictionnaire de test:
let d1 : [String:Any?] = ["1":Date(), "2":"two", "3":15, "4":true]
Nous sommes maintenant prêts à appliquer reduce
. Il transmet deux paramètres à sa fonction. Le premier est "l'accumulateur" où nous continuons à construire le résultat final, qui dans ce cas est un autre dictionnaire. Le second est un élément du dictionnaire d'origine, représenté par un Tuple de paires clé-valeur appelées key
et value
:
let d2 = d1.reduce([String:Any?]()) { (dict, Tuple) in
var dict = dict
dict[Tuple.key] = dateToSeconds(Tuple.value)
return dict
}
Et quand on examine d2
, nous voyons que nous avons la bonne réponse:
d2 // ["3": {some 15}, "2": {some "two"}, "1": {some 1486228695.557882}, "4": {some true}]
Je n'ai pas pu comprendre comment corriger cette erreur, et je n'ai pas réussi à obtenir le résultat souhaité avec une extension ou une map()
, mais j'ai une solution alternative au problème, en utilisant un fonction :
Déclaration du dictionnaire:
var date = NSDate()
var swiftDict:[String : Any?] = ["1": date, "2": "two", "3": 15, "4": true]
Fonction:
func firebaseFriendlyDictionary(_ dict: [String : Any?]) -> [String : Any?]{
var Dict = dict
for (key, value) in dict
{
if (value is NSDate){
Dict[key] = (value as! NSDate).timeIntervalSince1970
}
}
return Dict
}
Utilisation:
swiftDict = firebaseFriendlyDictionary(swiftDict)
Test:
En supposant que nous ayons la date 2017-02-04 16:42:46 +0000
la sortie est 1486226566.2349629
, qui est correct.
Pourquoi ne pas mapper le dictionnaire? Comme Losiowaty indiqué dans son excellente réponse, map
renvoie toujours un Array
, dans ce cas un Array
de Tuples ([T]
). À mon avis, une fonction de carte n'est pas nécessaire dans ce contexte, et elle nécessite plus de code à accomplir.
J'espère que cela t'aides!