使用可解码的 JSON 解析 [英] JSON Parsing using Decodable

查看:31
本文介绍了使用可解码的 JSON 解析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用可解码协议解析以下 JSON.我能够解析字符串值,例如 roomName.但我无法正确映射/解析所有者、管理员、成员键.例如,使用下面的代码,我可以解析所有者/成员中的值是否作为数组出现.但在某些情况下,响应将作为字符串值出现(请参阅 JSON 中的 owners 键),但我无法映射字符串值.

I am trying to parse the following JSON using decodable protocol. I am able to parse string value such as roomName. But I am not able to map/parse owners, admins, members keys correctly. For eg, using below code, I can able to parse if the values in owners/members are coming as an array. But in some cases, the response will come as a string value(see owners key in JSON), but I am not able to map string values.

注意:admins、members、owners 的值可以是字符串或数组(参见 JSON 中的所有者和成员键)

Note: Values of admins, members, owners can be string or array (see owners and members keys in JSON)

{
    "roomName": "6f9259d5-62d0-3476-6601-8c284a0b7dde",
    "owners": { 
        "owner": "anish@local.mac" //This can be array or string
    },
    "admins": null, //This can be array or string
    "members": {
        "member": [ //This can be array or string
            "steve@local.mac",
            "mahe@local.mac"
        ]
    }
}

型号:

 struct ChatRoom: Codable{
        var roomName: String! = ""
        var owners: Owners? = nil
        var members: Members? = nil
        var admins: Admins? = nil

        enum RoomKeys: String, CodingKey {
            case roomName
            case owners
            case members
            case admins
        }
       init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: RoomKeys.self)
            roomName = try container.decode(String.self, forKey: .roomName)
           if let member = try? container.decode(Members.self, forKey: .members) {
                members = member
            }
            if let owner = try? container.decode(Owners.self, forKey: .owners) {
                owners = owner
            }
            if let admin = try? container.decode(Admins.self, forKey: .admins) {
                admins = admin
            }
    }
}

//所有者模型

struct Owners:Codable{
    var owner: AnyObject?

    enum OwnerKeys:String,CodingKey {
        case owner
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: OwnerKeys.self)
        if let ownerValue = try container.decodeIfPresent([String].self, forKey: .owner){
            owner = ownerValue as AnyObject
        }
        else{
            owner = try? container.decode(String.self, forKey: .owner) as AnyObject
        }
    }

    func encode(to encoder: Encoder) throws {

    }
}

//成员模型

struct Members:Codable{
    var member:AnyObject?

    enum MemberKeys:String,CodingKey {
        case member
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: MemberKeys.self)
        if let memberValue = try container.decodeIfPresent([String].self, forKey: .member){
            member = memberValue as AnyObject
        }
        else{
            member = try? container.decode(String.self, forKey: .member) as AnyObject
        }
    }

    func encode(to encoder: Encoder) throws {

    }
}

推荐答案

这应该有效.为简单起见,我删除了 Admin 模型.我更喜欢 Owners/Members 是数组,因为它们可以有一个或多个值,这就是它们的用途,但是如果您希望它们成为 AnyObject,您可以像您已经在 <代码>init(decoder:).

This should work. I've removed Admin model for simplicity. I'd prefer Owners/Members to be arrays as they can have one or more values which is what they're for, but if you want them to be AnyObject, you can cast them as so like you're already doing in your init(decoder:).

测试数据:

var json = """
    {
        "roomName": "6f9259d5-62d0-3476-6601-8c284a0b7dde",
        "owners": {
            "owner": "anish@local.mac"
        },
        "admins": null,
        "members": {
            "member": [
            "steve@local.mac",
            "mahe@local.mac"
            ]
        }
    }
    """.data(using: .utf8)

模型:

struct ChatRoom: Codable, CustomStringConvertible {
    var roomName: String! = ""
    var owners: Owners? = nil
    var members: Members? = nil

    var description: String {
        let encoder = JSONEncoder()
        encoder.outputFormatting = .prettyPrinted
        let data = try? encoder.encode(self)
        return String(data: data!, encoding: .utf8)!
    }

    enum RoomKeys: String, CodingKey {
        case roomName
        case owners
        case members
        case admins
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: RoomKeys.self)
        roomName = try container.decode(String.self, forKey: .roomName)
        members = try container.decode(Members.self, forKey: .members)
        owners = try? container.decode(Owners.self, forKey: .owners)
    }
}

struct Owners:Codable{
    var owner: [String]?

    enum OwnerKeys:String,CodingKey {
        case owner
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: OwnerKeys.self)
        if let ownerValue = try? container.decode([String].self, forKey: .owner){
            owner = ownerValue
        }
        else if let own = try? container.decode(String.self, forKey: .owner) {
            owner = [own]
        }
    }
}

struct Members: Codable {
    var member:[String]?

    enum MemberKeys:String,CodingKey {
        case member
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: MemberKeys.self)
        if let memberValue = try? container.decode([String].self, forKey: .member){
            member = memberValue
        }
        else if let str = try? container.decode(String.self, forKey: .member){
            member = [str]
        }
    }
}

测试:

var decoder = JSONDecoder()
try? print("\(decoder.decode(ChatRoom.self, from: json!))")

输出:

{
  "owners" : {
    "owner" : [
      "anish@local.mac"
    ]
  },
  "members" : {
    "member" : [
      "steve@local.mac",
      "mahe@local.mac"
    ]
  },
  "roomName" : "6f9259d5-62d0-3476-6601-8c284a0b7dde"
}

这篇关于使用可解码的 JSON 解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆