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.