Have you tried JSONSerialization.jsonObject(with:options:)
?
var jsonString = "{" +
""Language": {" +
""Field":[" +
"{" +
""Number":"976"," +
""Name":"Test"" +
"}," +
"{" +
""Number":"977"," +
""Name":"Test"" +
"}" +
"]" +
"}" +
"}"
var data = jsonString.data(using: .utf8)!
let json = try? JSONSerialization.jsonObject(with: data)
Swift sometimes produces some very odd syntax.
if let number = json?["Language"]??["Field"]??[0]?["Number"] as? String {
print(number)
}
Everything in the JSON object hierarchy ends up getting wrapped as an optional (ie. AnyObject?
). Array<T>
subscript returns a non-optional T
. For this JSON, which is wrapped in an optional, array subscript returns Optional<AnyObject>
. However, Dictionary<K, V>
subscript returns an Optional<V>
. For this JSON, subscript returns the very odd looking
Optional<Optional<AnyObject>>
(ie. AnyObject??
).
json
is an Optional<AnyObject>
.
json?["Language"]
returns an Optional<Optional<AnyObject>>
.
json?["Language"]??["Field"]
returns an Optional<Optional<AnyObject>>
.
json?["Language"]??["Field"]??[0]
returns an Optional<AnyObject>
.
json?["Language"]??["Field"]??[0]?["Number"]
returns an Optional<Optional<AnyObject>>
.
json?["Language"]??["Field"]??[0]?["Number"] as? String
returns an Optional<String>
.
The Optional<String>
is then used by the if let
syntax to product a String
.
Final note: iterating the field array looks like this.
for field in json?["Language"]??["Field"] as? [AnyObject] ?? [] {
if let number = field["Number"] as? String {
print(number)
}
}
Swift 4 Update
Swift 4 makes this all much easier to deal with. Again we will start with your test data ("""
makes this so much nicer).
let data = """
{
"Language": {
"Field":[
{
"Number":"976",
"Name":"Test"
},
{
"Number":"977",
"Name":"Test"
}
]
}
}
""".data(using: .utf8)!
Next we can define classes around the objects used in your JSON.
struct Object: Decodable {
let language: Language
enum CodingKeys: String, CodingKey { case language="Language" }
}
struct Language: Decodable {
let fields: [Field]
enum CodingKeys: String, CodingKey { case fields="Field" }
}
struct Field: Decodable {
let number: String
let name: String
enum CodingKeys: String, CodingKey { case number="Number"; case name="Name" }
}
The CodingKeys
enum is how struct properties are mapped to JSON object member strings. This mapping is done automagically by Decodable
.
Parsing the JSON now is simple.
let object = try! JSONDecoder().decode(Object.self, from: data)
print(object.language.fields[0].name)
for field in object.language.fields {
print(field.number)
}