当对象包含其他对象数组时如何解析 JSON?

Posted

技术标签:

【中文标题】当对象包含其他对象数组时如何解析 JSON?【英文标题】:How to parse JSON when the object contains an array of other objects? 【发布时间】:2016-11-02 13:46:22 【问题描述】:

我一直在尝试在 Swift 中解析 JSON,其中对象包含其他对象的数组。像这样:


  "people": [
    
      "name": "Life Sciences",
      "id": "4343435",

      "children" : [
        
          "name": "name1",
          "id" : "5344444",
        ,

        
          "name": "name2",
          "id" : "5134343",
        ,
      .....

我需要能够访问 name 和 id 属性,但我似乎无法弄清楚我在下面的代码中做错了什么。我的 JSON 文件包含所有必要的数据,但是,当我尝试循环遍历子数组时,我不断收到 “unexpectedly found nil when unwrapping optional” 错误。在该行之前,JSON 被正确解析并正常工作。

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

【问题讨论】:

【参考方案1】:

你在这里犯了一个错误:

let jsonChildren = jsonResult?["children"] as! [AnyObject]

应该是:

let jsonChildren = jsonPerson["children"] as! [AnyObject]

【讨论】:

【参考方案2】:

可能,您的 JSON 数据在某些时候没有“子”值,请尽量避免强制转换为 [AnyObject]。您可以尝试以这种方式更改它:

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)
      

另外,您可以尝试使用SwiftyJSON,这将帮助您更轻松地进行 json 数据处理。

【讨论】:

【参考方案3】:

您的代码看起来不错,但问题是您正在搜索错误的字典。您的“jsonResult”键没有“儿童”键。但是你的 'jsonPerson' 对象有一个 'children' 键。替换下面的代码行 -

let jsonChildren = jsonResult?["children"] as! [AnyObject]

用这一行替换这一行 -

            let jsonChildren = jsonPerson?["children"] as! [AnyObject]

【讨论】:

【参考方案4】:

首先,JSON 并不代表代码中的实际 JSON。

其次,永远不要在 Swift 中使用 NSDictionary,除非你别无选择。

第三,将包含字典的 JSON 数组转换为 [[String:Any]],而不是 [Any(Object)]

第四,Swift 3 中的 JSON 字典是 [String:Any]

第五,使用可选绑定来避免运行时错误(崩溃)

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:您将收到另一个错误未定义标识符,因为您的代码中的子循环中的jsonEntrance 不存在并且childrenpeople 的键而不是根对象的键。

【讨论】:

以上是关于当对象包含其他对象数组时如何解析 JSON?的主要内容,如果未能解决你的问题,请参考以下文章

如何解析包含多个相同类型的 JSON 对象(不是数组)的 JSON 对象

如何使用 Newtonsoft.Json 将包含数组数组的 json 对象解析为 C# 中的对象列表?

使用 Node.js 解析不包含 JSON 对象的 JSON 数组

如何解析 JSON 数据对象内的数组内的数组?

如何仅将一些选定的 Json 数组和 Json 对象从 Url 解析到 android 设备

当某些返回值可能是对象或对象集合时,如何使用 GWT AutoBeans 解析 JSON 消息?