There are two standard ways to decode JSON in Swift:
JSONSerialization
JSONDecoder
The first leaves you with an untyped object hierarchy, so you have to walk the tree to find the data you need. For example:
let rootObj = try JSONSerialization.jsonObject(with: Data(input.utf8))
Here rootObj
is of type Any
, so you’ll need a bunch of as?
conversions to parse it.
The second approach involves declaring Swift types that map on to the JSON:
struct Item: Decodable {
var count: Int
}
struct MyData: Decodable {
var n: Int
var items: [Item]
init(from decoder: any Decoder) throws {
var container = try decoder.unkeyedContainer()
self.n = try container.decode(Int.self)
self.items = try container.decode([Item].self)
}
enum CodingKeys: CodingKey {
case n
case item
}
}
struct Parent: Decodable {
var data: [MyData]
}
struct Root: Decodable {
var parent: Parent
}
let root = try JSONDecoder().decode(Root.self, from: Data(input.utf8))
print(root)
The main complication here is MyData
. The corresponding JSON is this:
[
1705536000,
[
{
"count": 0
}
]
],
Note how the outermost type is an array but the elements of that array use different types (Int
and [Item]
). That means you can’t rely on the compiler-generated Decodable
implementation, because it uses container(keyedBy:)
which assumes a dictionary. You have to implement init(from:)
yourself, using unkeyedContainer()
to access the array.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"