在NSDictionary的数组对象中访问数组的第二级

时间:2018-09-18 06:03:56

标签: ios json swift nsdictionary arrayobject

我正在尝试NSDictionary的arrayobject中的第二级数组,但是它返回nil

我首先定义了NSDictionary,然后访问了数组的第一级,直到现在一切都很好为止。

let dict = JSON(responseObject as! NSDictionary)
let arrayData = dict["data"].arrayObject! as NSArray
print("arrayData", arrayData)

打印arrayData时,我得到以下回报

data =     (
{
categories = (
    {
    categories = "<null>";
    "category_id" = 333;
    image = "https://www.example.com/images/1.jpg";
    name = "Sub Category One";
    "parent_id" = 1000;
    },
    {
    categories = "<null>";
    "category_id" = 444;
    image = "https://www.example.com/images/2.jpg";
    name = "Sub Category Two";
    "parent_id" = 1000;
    },
    {
    categories = "<null>";
    "category_id" = 555;
    image = "https://www.example.com/images/3.jpg";
    name = "Sub Category Three";
    "parent_id" = 1000;
    }
);//end of categories array
"category_id" = 1000;
image = "https://www.examples.com/images/category.jpg";
name = "Parent Category";
"parent_id" = 0;
},
)

现在我正尝试从上面返回的数组访问并打印categories

所以我尝试了以下操作:

if dict["categories"].arrayObject != nil{
  let arrayData2 = dict["categories"].arrayObject! as NSArray
  print("arrayData2", arrayData2)
}

我也尝试过

if dict["data"]["categories"].arrayObject != nil{
  let arrayData2 = dict["data"]["categories"].arrayObject! as NSArray
  print("arrayData2", arrayData2)
}

两种方式都可以得到 nil 值,而应该获得真实值。

已编辑:在ViewController和dataModel结构中添加了API调用

View Controller中的callingHTTPAPI函数

func callingHttppApi(){
  DispatchQueue.main.async{
    NetworkManager.sharedInstance.showLoader()
    let sessionId = self.defaults.object(forKey:"token");
    self.categoriesTableView.isUserInteractionEnabled = false

      var requstParams = [String:Any]();
      requstParams["token"] = sessionId
      NetworkManager.sharedInstance.callingHttpRequest(params:requstParams, apiname:"api/cat", cuurentView: self){success,responseObject in
        if success == 1{
          let dict = responseObject as! NSDictionary;
          if dict.object(forKey: "fault") != nil{
            let fault = dict.object(forKey: "fault") as! Bool;
            if fault == true{
              self.loginRequest()
            }
          }else{
            NetworkManager.sharedInstance.dismissLoader()
            self.view.isUserInteractionEnabled = true
            self.categoriesTableView.isUserInteractionEnabled = true
            let dict = JSON(responseObject as! NSDictionary)
            let arrayData = dict["data"].arrayObject! as NSArray
            if dict["categories"].arrayObject != nil{
              let arrayData2 = dict["categories"].arrayObject! as NSArray
              print("arrayData2", arrayData2)
            }
            print("arrayData", arrayData)
            if dict["error"].intValue == 1{
              NetworkManager.sharedInstance.showErrorMessageWithBack(view: self, message: NetworkManager.sharedInstance.language(key: "error"))
            }else{
              self.categoriesCollModel = CategoriesViewModel(data:JSON(responseObject as! NSDictionary))
              dump (self.categoriesCollModel)
            }
          }
        }else if success == 2{
          NetworkManager.sharedInstance.dismissLoader()
          self.callingHttppApi()
        }
      }
    }
  }

用于投射值的dataModel结构

//
//  CategoriesViewModel.swift
//

import Foundation

class Categories: NSObject{
    var id:String = ""
    var name:String = ""
    var image:String = ""

    init(data:JSON){
        self.id = data["category_id"].stringValue
        self.name  = data["name"].stringValue
        self.image = data["image"].stringValue
    }

}

class SubCategories:NSObject{
    var pid:String = ""
    var id:String = ""
    var name:String = ""
    var image:String = ""

    init(data:JSON) {
        self.pid = data["parent_id"].stringValue
        self.id = data["category_id"].stringValue
        self.name  = data["name"].stringValue
        self.image = data["image"].stringValue
    }

}

struct Categories_Data{
    var id:String = ""
    var categoriesArray = [SubCategories]()

    init(data:JSON) {
        self.id = data["category_id"].stringValue
        if let arrayData = data["data"]["categories"].arrayObject {
            categoriesArray =  arrayData.map({(value) -> SubCategories in
                return  SubCategories(data:JSON(value))
            })
        }
    }

}

class CategoriesViewModel:NSObject{
    var categoryModel = [Categories]()
    var subCategories = [SubCategories]()
  var categories_Data = [Categories_Data]()

    init(data:JSON) {

        let arrayData = data["data"].arrayObject! as NSArray
        categoryModel =  arrayData.map({(value) -> Categories in
            return  Categories(data:JSON(value))
        })

        if data["data"]["categories"].arrayObject != nil{
            let arrayData2 = data["data"]["categories"].arrayObject! as NSArray
            categories_Data =  arrayData2.map({(value) -> Categories_Data in
                return  Categories_Data(data:JSON(value))
            })
        }

        //categoryModel = Categories(data:data)


    }

    var getCategories:Array<Categories>{
        return categoryModel
    }

  var getSubCategories:Array<SubCategories>{
        return subCategories
    }

}

5 个答案:

答案 0 :(得分:3)

我强烈建议放下SwiftyJSON并使用Decodable

CategoriesViewModel可以简化为

struct Root: Decodable {
    let data : [Category]
}

struct Category: Decodable {
    let categories : [Category]?
    let categoryId : Int
    let image : URL
    let name : String
    let parentId : Int
}

您需要从网络请求中获取原始数据(在下面的名为data的代码中),然后您可以简单地将数据解码为结构并使用点符号获取值。

我添加了一个辅助函数,可以递归地打印嵌套的类别

do {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let result = try decoder.decode(Root.self, from: data)
    printCategories(result.data)
} catch { print(error) }

func printCategories(_ categories : [Category]) {
    for item in categories {
        if let subCategories = item.categories {
            printCategories(subCategories)
        }
        print(item.name, item.categoryId)
    }
}

答案 1 :(得分:0)

您以错误的方式检索对象。始终使用check nil值检索对象或值...
检查以下代码以检索您的类别。

let dict = JSON(responseObject as! NSDictionary)
    if let data = dict["data"] as? Array<Any>
    {
        if let categoryArray = data["categories"] as? Array<Dictionary<String,Any>>
        {
            if categoryArray.count > 0
            {
                print(categoryArray)
            }
        }
    }

答案 2 :(得分:0)

看起来很复杂,但是非常简单,只需遵循层次结构

例如,说您要访问“数据->类别->名称”,因为您可以在回复中像这样

这是您的主要词典,里面包含了所有内容。

if let dict = responceObject as? NSDictionary {
// now lets say you want go to your categories which is array of dictionaries

  if let arrDict = dict["categories"] as? NSArray {
      print("arrDict")

      // Now you can go anywhere in that array of dictionaries
      // For example you want to get name you can do like this

      for obj in arrDict {
         if let name = obj["name"] as? String {
            print(name)
         }
      }
  }
}

我要在此处添加编辑部分

// In your webcall lets say you receive a JSON(i am naming it as "json") object with type Any
if let jsonObj = json as? [String: Any], let mainDict = jsonObj["data"] as? [[String: Any]] {
    for arr in mainDict {
       if let arrDict = arr["categories"] as? [[String: Any]] {
           print(arrDict)
           // Now you can dig that dict which is array of dictionaries
           for obj in arrDict {
              if let name = obj["name"] as? String {
                 print(name)
              }

              if let id = obj["id"] as? Int { // Int or whatever it is
                 print(id)  
              } 
           }
       }
    }
}

希望这会起作用。

答案 3 :(得分:0)

初始化模型对象时,还应该使用guard来验证值:

init(data: JSON) {
    guard
        let id = data["category_id"] as? Int,
        let name = data["name"] as? String,
        let image = data["image"] as? String
        else {
             return
        }
    self.id = id
    self.name  = name
    self.image = image
}

请注意,id是整数值,而不是字符串,因此您应该更改模型。

还可以检出Codable

答案 4 :(得分:0)

首先了解print("arrayData", arrayData)的响应。它是array中的Dictionaries

添加时:

let arrayData = dict["data"].arrayObject! as NSArray

您正在将数据保存在dictionary中的数组中。

现在要获取类别,您必须使用arrayData

let firstDict = arrayData[0] as! [String:Any]
let arrayData2 = firstDict["categories"] as! [[String:Any]]
print("arrayData2", arrayData2)

我添加了此代码以显示一个数据。

有关更多数据,您可以用于循环:

for dictData in arrayData {
    let arrayData2 = dictData["categories"] as! [[String:Any]]
    print("arrayData2", arrayData2)
}

并使用此循环可以管理或保存相关数据。

还有一件别忘了添加零处理部分。

快速处理时的另一件事不要使用NSArrayNSDictionary

尝试使用Codable。互联网上有很多示例,可以使您的代码更简洁。