web-dev-qa-db-fra.com

Array.map () produit '[T]', pas le type de résultat contextuel attendu '[String: Any?]'

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?]'

15
Liau Jian Jie

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.

6
Losiowaty

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}]
6
matt

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!

4
Mr. Xcoder