Swift `Decodable` does not work for nested JSON objects if nested is an array

I started converting some JSON parsing code to use the new Apple Decodable protocol, and ended up in a blocker that feels too fundamental when it was missed during Apple testing, so I wonder if I'm doing something stupid. In short, I am trying to parse the JSON graph this way, and since I am only decrypting, I thought Decodable should be sufficient for matching, but it seems due to the errors that I need to match Codable (Decodable and Encodable ) to get the desired decoding effect:

 {"keyString": {"nestedKey1" : "value1", "nestedKey1" : "value1" } } 

It works with this case:

 {"keyString": [{"nestedKey1" : "value1", "nestedKey1" : "value1" } ]} 

as is an array of nested objects, but not for a single object.

Is this a Swift bug or am I not understanding something?

Here is an example site that can prove this problem. If the Animal class matches Decodable , it doesn't parse the array, but if I Codable Animal to match Codable , then it really works. I would not expect this to be so, because I am only decrypting JSON here.

 import Foundation //class Animal: Codable { class Animal: Decodable { var fileURLPath: String = "" var age: Double = 0 var height: Double = 0 var weight: Double = 0 private enum CodingKeys: String, CodingKey { case fileURLPath = "path" case age case height case weight } required init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) fileURLPath = try values.decode(String.self, forKey: .fileURLPath) age = try values.decode(TimeInterval.self, forKey: .age) height = try values.decode(Double.self, forKey: .height) weight = try values.decode(Double.self, forKey: .weight) } } let innerObjectJSON = """ { "path": "tiger_pic.png", "age": 9, "height": 1.23, "weight": 130 } """ let innerObjectData = innerObjectJSON.data(using: String.Encoding.utf8) let jsonDataNestedObject = """ { "en" : \(innerObjectJSON) } """.data(using: String.Encoding.utf8) let jsonDataNestedArray = """ { "en" : [\(innerObjectJSON), \(innerObjectJSON), \(innerObjectJSON) ] } """.data(using: String.Encoding.utf8) print("Nested Array of Objects:") do { let result = try JSONDecoder().decode([String: [Animal]].self, from: jsonDataNestedArray!) result["en"]!.forEach ({ print($0.fileURLPath) }) // This one works } catch { print(error) } print("\n\n Single Object:") do { let result = try JSONDecoder().decode(Animal.self, from: innerObjectData!) print(result.fileURLPath) } catch { print(error) } print("\n\nNested Object:") do { let result = try JSONDecoder().decode([String: Animal].self, from:jsonDataNestedObject!) print(result["en"]!.fileURLPath) // I would also expect this to work but I get the error: "fatal error: Dictionary<String, Animal> does not conform to Decodable because Animal does not conform to Decodable.: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.45.6/src/swift/stdlib/public/core/Codable.swift, line 3420" } catch { print(error) } 
+5
source share

Source: https://habr.com/ru/post/1269120/


All Articles