7 votes

L'utilisation de flatMap avec des dictionnaires produit des tuples ?

J'ai ce mappage assez basique et direct d'un objet dans un dictionnaire. J'utilise un dictionnaire d'analyse syntaxique au niveau supérieur. L'un de ses champs est un tableau d'autres dictionnaires. Pour les définir, j'utilise flatMap qui semble être une méthode appropriée mais puisque l'objet à l'intérieur n'est pas nullable, cette méthode renvoie soudainement des tuples (du moins il semble que ce soit le cas) au lieu de dictionnaires.

J'ai créé un exemple minimum qui peut être collé dans un nouveau projet à peu près partout où l'une de vos exécutions se produit et qui devrait donner plus de détails que n'importe quelle description :

func testFlatMap() -> Data? {

    class MyObject {
        let a: String
        let b: Int
        init(a: String, b: Int) { self.a = a; self.b = b }

        func dictionary() -> [String: Any] {
            var dictionary: [String: Any] = [String: Any]()
            dictionary["a"] = a
            dictionary["b"] = b
            return dictionary
        }
    }

    let objects: [MyObject] = [
        MyObject(a: "first", b: 1),
        MyObject(a: "second", b: 2),
        MyObject(a: "third", b: 3)
    ]

    var dictionary: [String: Any] = [String: Any]()
    dictionary["objects"] = objects.flatMap { $0.dictionary() }
    dictionary["objects2"] = objects.map { $0.dictionary() }

    print("Type of first array: " + String(describing: type(of: dictionary["objects"]!)))
    print("Type of first element: " + String(describing: type(of: (dictionary["objects"] as! [Any]).first!)))

    print("Type of second array: " + String(describing: type(of: dictionary["objects2"]!)))
    print("Type of second element: " + String(describing: type(of: (dictionary["objects2"] as! [Any]).first!)))

    return try? JSONSerialization.data(withJSONObject: dictionary, options: [])
}
_ = testFlatMap()

Ce code se plante donc en disant

NSInvalidArgumentException', reason : 'Invalid type in JSON write (_SwiftValue)''.

(L'utilisation de do-catch ne fait aucune différence, ce qui est le premier WTH, mais laissons cela pour le moment).

Regardons donc ce que dit le journal :

Type of first array: Array<(key: String, value: Any)>
Type of first element: (key: String, value: Any)
Type of second array: Array<Dictionary<String, Any>>
Type of second element: Dictionary<String, Any>

Le second est ce que nous attendons, mais le premier ne contient que des tuples. Est-ce naturel, intentionnel ?

Avant que vous ne vous lanciez dans le "pourquoi utiliser flatMap pour les valeurs non optionnelles", laissez-moi vous expliquer que func dictionary() -> [String: Any] utilisé pour être func dictionary() -> [String: Any]? parce qu'il a ignoré les éléments pour lesquels il manquait des données.

Donc, il suffit d'ajouter ce petit ? à la fin de cette méthode changera la sortie en :

Type of first array: Array<Dictionary<String, Any>>
Type of first element: Dictionary<String, Any>
Type of second array: Array<Optional<Dictionary<String, Any>>>
Type of second element: Optional<Dictionary<String, Any>>

ce qui signifie que la première solution est la bonne. Et lors du changement, il n'y a aucun avertissement, rien. L'application se met soudainement à planter.

La question qui se pose à la fin est évidemment "Comment éviter cela ?" sans trop de travail. En utilisant dictionary["objects"] = objects.flatMap { $0.dictionary() } as [[String: Any]] semble faire l'affaire pour préserver une seule ligne. Mais l'utilisation de cette méthode semble très stupide.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X