从json解析三个对象的数组

Posted

技术标签:

【中文标题】从json解析三个对象的数组【英文标题】:parsing array of three objects from json 【发布时间】:2018-05-02 06:21:39 【问题描述】:

我有 3 个对象(国籍、服务和包),我从 JSON 响应中获取它们作为这些对象的 3 个数组。我想从 JSON 响应中解析它们...

类是:

struct Root2 : Decodable 
let nationalities : [Nationalities]
let services : [Services]
let packages : [Packages]


struct Packages : Decodable 
let id: Int
let name: String
let idService: Int
let nationality: String
let totalPrice: Int
let visitsPerWeek: Int
let excludedDays: String
let excludedShifts: String
let excludedDates: String
let extraVisits: Int
let dateEnabled: String
let dateDisabled: String
let allowedFrom: String
let allowedTo: String
let visitType: String
let createdAt: String?
let updatedAt: String?
 
 struct Nationalities : Decodable
let id: Int
let name: String
let createdAt: String?
let updatedAt: String?

struct Services : Decodable
let id: Int
let name, description: String
let createdAt: String?
let updatedAt: String?

我每个人都有另一个类,例如:

class Service : NSObject, NSCoding 
var id: Int
var name, desc: String
var createdAt: String?
var updatedAt: String?


init(id: Int, name: String, desc: String) 
    self.id = id
    self.name = name
    self.desc = desc



required convenience init(coder aDecoder: NSCoder) 
    let id = aDecoder.decodeInteger(forKey: "id")
    let name = aDecoder.decodeObject(forKey: "name") as! String
    let desc = aDecoder.decodeObject(forKey: "desc") as! String
    self.init(id: id, name: name, desc: desc)


func encode(with aCoder: NSCoder) 
    aCoder.encode(id, forKey: "id")
    aCoder.encode(name, forKey: "name")
    aCoder.encode(desc, forKey: "desc")



我是这样使用它的:

 func GetServicesPackagesNationalities()

let link: String = "my link"
guard let url = URL(string: link) else 
    print("Error: cannot create URL")
    return

let urlRequest = URLRequest(url: url)

let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)

let task = session.dataTask(with: urlRequest) 
    (data, response, error) in
    guard error == nil else 
        print("error calling GET on /public/api/services")
        print(error!)
        return
    
    guard let responseData = data else 
        print("Error: did not receive data")
        return
    
    do 

        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        let result = try decoder .decode(Root2.self, from: responseData)


        var nationalities = [Nationality]()
        for nationality in result.nationalities
            let newnationality = Nationality(id: nationality.id, name: nationality.name)
            nationalities.append(newnationality)
            print(newnationality.name)
        


        var services = [Service]()
        for service in result.services 
            let newservice = Service(id: service.id, name: service.name, desc: service.description)
            services.append(newservice)
            print(newservice.name)
        


       var packages = [Package]()
        for package in result.packages
            let newpackage = Package(id: package.id, name: package.name, idService: package.idService, nationality: package.nationality, totalPrice: package.totalPrice, visitsPerWeek: package.visitsPerWeek, excludedDays: package.excludedDays, excludedShifts: package.excludedShifts, excludedDates: package.excludedDates, extraVisits: package.extraVisits ,dateEnabled: package.dateEnabled , dateDisabled: package.dateDisabled, allowedFrom: package.allowedFrom, allowedTo: package.allowedTo ,visitType: package.visitType)
            packages.append(newpackage)
            print(newpackage.name)
        



    catch  
        print("error trying to convert data to JSON")
        return
    

task.resume()
 

我永远都会得到这个:

尝试将数据转换为 JSON 时出错

我的 json 是:

   
"nationalities": [
    
        "id": 1,
        "name": "Saudi Arabia",
        "created_at": "2018-04-24 05:50:41",
        "updated_at": "2018-04-24 06:35:29",
        "deleted_at": null
    ,
    
        "id": 2,
        "name": "Bahrain",
        "created_at": "2018-04-24 05:52:52",
        "updated_at": "2018-04-24 05:52:52",
        "deleted_at": null
    ,
],
"services": [
    
        "id": 1,
        "name": "Nad",
        "description": "Nad ",
        "created_at": null,
        "updated_at": null,
        "deleted_at": null
    ,
    
        "id": 2,
        "name": "Reay",
        "description": "Re ",
        "created_at": null,
        "updated_at": null,
        "deleted_at": null
    ,
],
"packages": [
    
        "id": 1,
        "name": "Gold Package",
        "id_service": 1,
        "nationality": "4",
        "total_price": 1000,
        "visits_per_week": 2,
        "excluded_weekdays": "null",
        "excluded_shifts": "null",
        "excluded_dates": "1111-11-11",
        "extra_visits": 1,
        "date_enabled_from": "2018-04-01",
        "date_enabled_to": "2018-04-30",
        "date_allowed_from": "2018-04-05",
        "date_allowed_to": "2018-04-30",
        "visit_type": "Multi",
        "created_at": "2018-04-26 11:18:45",
        "updated_at": "2018-04-26 11:18:45",
        "deleted_at": null
    
]

我不知道我做错了什么..因为我对两个对象进行了相同的尝试并且工作正常..

谁能告诉我我做错了什么?

在用户默认值中使用它们:

存储:

     let userDefaults = UserDefaults.standard


        let encodedData: Data = NSKeyedArchiver.archivedData(withRootObject: services)
        userDefaults.set(encodedData, forKey: "services")
        userDefaults.synchronize()

检索:

        let decoded  = userDefaults.object(forKey: "services") as! Data
        let decodedService = NSKeyedUnarchiver.unarchiveObject(with: decoded) as! [Service]

        for service in decodedService 
            print(service.name)
        

【问题讨论】:

【参考方案1】:

永远不要catch 子句中打印无意义的文字字符串,始终打印实际的错误,它会告诉您究竟出了什么问题

 catch  
    print(error)


Package 有很多问题,这里是错误消息(以及修复它们的建议):

"没有与键 CodingKeys 关联的值(stringValue: \"excludedDays\",转换为excluded_days。"

JSON 中没有键 excluded_days删除该属性或将其声明为可选 (String?)

"没有与键 CodingKeys 关联的值(stringValue: \"dateEnabled\" 转换为 date_enabled。"

实际的snake_case转换属性应该是dateEnabledFrom

"没有与键 CodingKeys 关联的值(stringValue: \"dateDisabled\" 转换为 date_disabled。"

JSON 中没有键 date_disabled删除该属性或将其声明为可选 (String?)

"没有与键 CodingKeys 关联的值(stringValue: \"allowedFrom\", intValue: nil) (\"allowedFrom\"),转换为allowed_from。"

实际的snake_case 转换属性应该是dateAllowedFrom

"没有与键 CodingKeys 关联的值(stringValue:\"allowedTo\", intValue: nil) (\"allowedTo\"),转换为allowed_to。"

实际的snake_case转换属性应该是dateAllowedTo

注意:

你为什么要为Nationality, Service, Package 使用另一个额外的类?它们似乎是多余的。如果您确实需要引用语义,请将 JSON 解码为类。

【讨论】:

谢谢你的工作.. 我会记住始终使用 print(error) 请注意您的笔记.. 我这样做是为了将它们存储在 userdefaults 中.. 如果您可以查看我更新后的帖子的最后一部分.. 有更好的方法吗? JSON 符合属性列表。您可以将结构编码(到 JSON 甚至属性列表)并直接保存 Data 表示。【参考方案2】:

查看NationalityNationalities 之间的区别

您应该使用Nationalities 来解析您的 JSON 响应。

你应该这样做,因为你已经在 Root2 中声明了 Nationalities 对象

var nationalities = [Nationalities]()
for nationality in result.nationalities
    let newnationality = Nationalities(id: nationality.id, name: nationality.name)
    nationalities.append(newnationality)
    print(newnationality.name)

ServicesPackages 相同,请查找。

【讨论】:

交叉验证您创建的结构中的所有密钥

以上是关于从json解析三个对象的数组的主要内容,如果未能解决你的问题,请参考以下文章

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

如何从通过 Moya.Response 查询返回的对象解析嵌套的 JSON 数组

从 Component 中的 Service 解析 JSON 数组对象

为啥不能从文件中解析 JSON?

解析 JSON 文件(本地存储),从而快速创建对象数组

Python 解析 JSON 数组