Reputation: 27
I've been trying to parse a JSON in Swift where the object contains an array of other objects. Like this:
{
"people": [
{
"name": "Life Sciences",
"id": "4343435",
"children" : [
{
"name": "name1",
"id" : "5344444",
},
{
"name": "name2",
"id" : "5134343",
},
.....
I need to be able to access the name and id properties, but I can't seem to figure out what I'm doing wrong with my code below. My JSON file contains all the necessary data, yet, I keep getting the "unexpectedly found nil when unwrapping optional" error when I try to loop over the children array. Before that line the JSON is parsed correctly and works.
let loadURL = "https:// ....."
var people = [Person]()
func getPersonData() {
let request = URLRequest(url: URL(string: loadURL)!)
let urlSession = URLSession.shared
let task = urlSession.dataTask(with: request, completionHandler: { (data, response, error) -> Void in
if let error = error {
print(error)
return
}
// Parse JSON data
if let data = data {
self.people = self.parseJsonData(data)
OperationQueue.main.addOperation{() -> Void in
self.tableView.reloadData()
}
}
})
task.resume()
}
func parseJsonData(_ data: Data) -> [Person] {
var people = [Person]()
do {
let jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
// Parse JSON data
let jsonPeople = jsonResult?["people"] as! [AnyObject]
for jsonPerson in jsonPeople {
let person = Person()
person.name = jsonPerson["name"] as! String
person.id = jsonPerson["id"] as! String
//ERROR//: "unexpectedly found nil when unwrapping optional..."
let jsonChildren = jsonResult?["children"] as! [AnyObject]
for jsonChild in jsonChildren {
let child = Child()
child.name = jsonEntrance["name"] as! String
child.age = jsonEntrance["age"] as! Int
person.children.append(child)
}
people.append(person)
}
} catch {
print(error)
}
return people
}
Upvotes: 0
Views: 958
Reputation: 285082
First of all, the JSON does not represent the actual JSON in the code.
Second of all, never ever use NSDictionary
in Swift unless you have no choice.
Third of all, cast an JSON array containing dictionaries to [[String:Any]]
, never to [Any(Object)]
Fourth of all, a JSON dictionary in Swift 3 is [String:Any]
Fifth of all, use optional bindings to avoid runtime errors (crashes)
func parseJsonData(_ data: Data) -> [Person] {
var people = [Person]()
do {
let jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String:Any]
// Parse JSON data
if let jsonPeople = jsonResult["people"] as? [[String:Any]] {
for jsonPerson in jsonPeople {
let person = Person()
person.name = jsonPerson["name"] as! String
person.id = jsonPerson["id"] as! String
// children is a key of a person not of the root object !
if let jsonChildren = jsonPerson["children"] as? [[String:Any]] {
for jsonChild in jsonChildren {
let child = Child()
child.name = jsonChild["name"] as! String
child.age = jsonChild["age"] as! Int
person.children.append(child)
}
}
people.append(person)
}
}
} catch {
print(error)
}
return people
}
PS: You will get another error undefined identifier because jsonEntrance
in the child loop in your code does not exist and children
is a key of people
not of the root object.
Upvotes: 0
Reputation: 2403
Your code looks good, but the problem is that you are search for wrong dictionary. Your 'jsonResult' key doesn't have a key for 'children'. But your 'jsonPerson' object has a 'children' key. Replace your below line of code -
let jsonChildren = jsonResult?["children"] as! [AnyObject]
Replace this line with this one -
let jsonChildren = jsonPerson?["children"] as! [AnyObject]
Upvotes: 0
Reputation: 2196
You made an error here:
let jsonChildren = jsonResult?["children"] as! [AnyObject]
Should be:
let jsonChildren = jsonPerson["children"] as! [AnyObject]
Upvotes: 1
Reputation: 702
Probably, your JSON data on some point has no "children" value, try to avoid force casting to [AnyObject]. You may try to change it in this way:
if let result = jsonResult, let jsonChildren = result["children"] as? [AnyObject] {
for jsonChild in jsonChildren {
let child = Child()
child.name = jsonEntrance["name"] as! String
child.age = jsonEntrance["age"] as! Int
person.children.append(child)
}
}
Also, you may try use SwiftyJSON which will help you to do your json data processing much more easier.
Upvotes: 0