{
"values":[
[1,1,7,"Azuan Child","Anak Azuan","12345","ACTIVE","Morning",7,12,"2017-11-09 19:45:00"],
[28,1,0,"Azuan Child2","Amran","123456","ACTIVE","Evening",1,29,"2017-11-09 19:45:00"]
]
}
Ok, this is my json format that i received from the server
Right now i want to decode it into my struct but still have no luck on it.
struct ChildrenTable: Decodable {
var values: [[String]]?
}
And my caller method on URLSession look like this
URLSession.shared.dataTask(with: request) { (data, response, err) in
guard let data = data else { return }
let dataAsString = String(data: data, encoding: .utf8)
print(dataAsString)
do {
let children = try
JSONDecoder().decode(ChildrenTable.self, from: data)
print (children)
} catch let jsonErr {
print ("Error serializing json: ", jsonErr)
}
}.resume()
And the error that i got are
Error serializing json:
typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [Vito_Parent.ChildrenTable.(CodingKeys in _1B826CD7D9609504747BED0EC0B7D3B5).values, Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 0", intValue: Optional(0)),
Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 0", intValue: Optional(0))],
debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil))
I know there's an int in the array and i only cast String for the values var values: [[String]]? ( the reason why this error popup), but i simply cannot use any multidimensional array or tuples in my structs since it follow the protocol of Decodable.
I also cannot convert the data into dictionary since it will throw error "Expected to decode Dictionary but found array instead"
Any ideas on solving this problem? i tried casting string type on data but still no luck...
p/s: if all the json format are in string type, there would be no problem, but i dont have the permission on changing that since i call it from API.
As you said, your json array is multi-type but you are trying to decode all into String. Default conformance of String to Decodable does not allow that. The only solution comes into my mind is to introduce new type.
struct IntegerOrString: Decodable {
var value: Any
init(from decoder: Decoder) throws {
if let int = try? Int(from: decoder) {
value = int
return
}
value = try String(from: decoder)
}
}
struct ChildrenTable: Decodable {
var values: [[IntegerOrString]]?
}
Run online
Observe that the inner arrays in the JSON have a patterned sequence of types, and we know what that sequence is. The types in the inner arrays are in a patterned sequence: 3 Ints, 5 Strings, 2 Ints, and something probably intended as a Date. Clearly, in the minds of the JSON designers, each of these 11 elements has a fixed and known meaning.
This means that we can pick up the 11 elements one by one, manually, by dumpster-diving and decoding the entire JSON expression manually.
The arrays have mixed types, and Swift doesn't like that, so we will have to express them as an array of Any (or of AnyObject); but we can obtain them as themselves, rather than having to wrap them up in an artificial intermediate struct.
By the way, if you know what the meaning of each element is, then instead of an array of Any, you can decode the inner array into a struct with 11 named properties that express what each element signifies. That would be a cleaner result, but I have not used it because I do not know the meanings of the 11 values.
Here we go:
struct S : Decodable {
var values : [[Any]]
enum CodingKeys : String, CodingKey {
case values
}
init(from decoder: Decoder) throws {
// get the dictionary
let con = try! decoder.container(keyedBy: CodingKeys.self)
// get the "values" array of array
var con2 = try! con.nestedUnkeyedContainer(forKey: CodingKeys.values)
var bigarr = [[Any]]()
for _ in 0..<con2.count! {
// get a nested array
var con3 = try! con2.nestedUnkeyedContainer()
// decode all the elements of the nested array
var arr = [Any]()
arr.append(try! con3.decode(Int.self))
arr.append(try! con3.decode(Int.self))
arr.append(try! con3.decode(Int.self))
arr.append(try! con3.decode(String.self))
arr.append(try! con3.decode(String.self))
arr.append(try! con3.decode(String.self))
arr.append(try! con3.decode(String.self))
arr.append(try! con3.decode(String.self))
arr.append(try! con3.decode(Int.self))
arr.append(try! con3.decode(Int.self))
arr.append(try! con3.decode(String.self))
bigarr.append(arr)
}
// all done! finish initialization
self.values = bigarr
}
}
let result = try! JSONDecoder().decode(S.self, from: jdata)
print(result.values)
// [[1, 1, 7, "Azuan Child", "Anak Azuan", "12345", "ACTIVE",
// "Morning", 7, 12, "2017-11-09 19:45:00"],
// [28, 1, 0, "Azuan Child2", "Amran", "123456", "ACTIVE",
// "Evening", 1, 29, "2017-11-09 19:45:00"]]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With