Codable使用

作者: kawa007 | 来源:发表于2018-02-28 14:04 被阅读0次

    准备JSON数据

    let sample1Json = """
    {
        "id": 1000,
        "name": "基金1",
        "review": null,
    }
    """
    
    let sample2Json = """
    [
        {
        "id": 1000,
        "name": "基金1",
        "review": "收益高+期限短"
        },
        {
        "id": 1001,
        "name": "基金2",
        "review": "适合短期投资"
        }
    ]
    """
    
    let sample3Json = """
    {
        "text": "Agree!Nice weather!",
        "user": {
            "name": "Jack",
            "icon": "lufy.png"
        },
        "retweetedStatus": {
            "text": "nice weather",
            "user": {
                "name": "Rose",
                "icon": "nami.png"
            }
        }
    }
    """
    
    let sample4Json = """
    {
        "check0": true,
        "check1": 1,
    }
    """
    
    let sample5Json = """
    {
        "date": "2017-11-16T02:02:55.000-08:00"
    }
    """
    

    1、基本模型解析

    Sample.swift

    class Sample: Codable {
        var id: Int?
        var name: String?
        var review: String?
    }
    

    json转model,一行代码搞定

    let data = sample1Json.data(using: .utf8)
    do {
        // decode 解码
        let x: Sample = try JSONDecoder().decode(Sample.self, from: data!)
    } catch {
        print(error)
    }
    

    解析之后的结果如下:

    (lldb) p x
    (CodableDemo.Sample) $R0 = 0x00006040000b0c80 {
      id = 1000
      name = "基金1"
      review = nil 
    }
    (lldb) 
    

    2、模型解析-自定义key

    class Sample: Codable {
        var id: Int32?
        var re_name: String?
        var review: String?
    
        enum CodingKeys: String, CodingKey {
            case id
            case re_name = "name" /// 自定义key
            case review
        }
    }
    

    注意:如果需要自定义key,所有key都需要在CodingKeys中定义,否则会报error: Type 'Sample' does not conform to protocol 'Decodable'这个错误

    json解析代码同上

    解析结果如下:

    (lldb) p x
    (CodableDemo.Sample) $R0 = 0x00006000000af000 {
      id = 1000
      re_name = "基金1"
      review = nil
    }
    (lldb) 
    

    3、嵌套模型解析

    Status.swift

    class Status: Codable {
        var text: String?
        var user: User?
        var retweetedStatus: Status?
    }
    
    class User: Codable {
        var name: String?
        var icon: String?
    }
    

    json->model解析

    let data = sample3Json.data(using: .utf8)
    do {
        let status: x = try JSONDecoder().decode(Status.self, from: data!)
        print(x)
    } catch {
        print(error)
    }
    

    解析结果如下:

    (lldb) p x
    (CodableDemo.x) $R1 = 0x000060000026dc80 {
      text = "Agree!Nice weather!"
      user = 0x0000600000091c60 {
        name = "Jack"
        icon = "lufy.png"
      }
      retweetedStatus = 0x0000608000076380 {
        text = "nice weather"
        user = 0x000060800008aaf0 {
          name = "Rose"
          icon = "nami.png"
        }
        retweetedStatus = nil
      }
    }
    (lldb) 
    
    

    4、模型数组

    解析模型数组:

    let data = sample2Json.data(using: .utf8)
    do {
        // decode 解码
        let x: [Sample] = try JSONDecoder().decode([Sample].self, from: data!)
        print(x)
    } catch {
        print(error)
    }
    

    解析结果:

    (lldb) p x
    ([CodableDemo.Sample]) $R0 = 2 values {
      [0] = 0x00006080000aace0 {
        id = 1000
        re_name = "基金1"
        review = "收益高+期限短"
      }
      [1] = 0x00006000000a92a0 {
        id = 1001
        re_name = "基金2"
        review = "适合短期投资"
      }
    }
    (lldb) 
    

    5、自定义编码解码方法

    如果JSON数据不能按预期解析,可以通过自定义编码解码方法,得到预期的解析结果

    class Sample: Codable {
        var id: Int?
        var name: String?
        var review: String?
    
        enum CodingKeys: String, CodingKey {
            case id
            case name
            case review
        }
    
        // 自定义编码方法
        public func encode(to encoder: Encoder) throws {
            // 使用CodingKeys创建编码器
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(id, forKey: CodingKeys.id)
            try container.encode(name, forKey: CodingKeys.name)
            try container.encode(review, forKey: CodingKeys.review)
        }
    
        // 自定义解码方法
        public required init(from decoder: Decoder) throws {
            // 使用CodingKeys创建解码器
            let container = try decoder.container(keyedBy: CodingKeys.self)
            id = try container.decode(Int.self, forKey: CodingKeys.id)
            name = try container.decode(String.self, forKey: CodingKeys.name)
            review = try container.decode(String.self, forKey: CodingKeys.review)
        }
    }
    

    6、日期解析

    Sample.swift

    class Sample: Codable {
        var date: String?
    
        enum CodingKeys: String, CodingKey {
            case date
        }
    
        public required init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            let dateString = try container.decode(String.self, forKey: CodingKeys.date1)
            let format = DateFormatter()
            format.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
            let tempDate = format.date(from: dateString)
            format.dateFormat = "yyyy-MM-dd HH:mm:ss"
            date = format.string(from: tempDate!)
        }
    }
    

    解析:

    let data = sample5Json.data(using: .utf8)
    do {
        let decoder = JSONDecoder()
        let x: Sample = try decoder.decode(Sample.self, from: data!)
        print(x)
    } catch {
        print(error)
    }
    

    解析结果:

    (lldb) p x
    (CodableDemo.Sample2) $R0 = 0x000060800024fea0 {
      date1 = "2017-11-16 18:02:55"
    }
    (lldb) 
    

    7、Bool值解析

    codable只能解析true/false,其他类型(例如:1/0)的值会报类型不匹配的错误Expected to decode Bool but found a number instead.,如果后台返回的类型不是true/false需要额外处理

    Sample.swift

    class Sample: Codable {
        var check0: Bool?
        var check1: Bool?
    
        enum CodingKeys: String, CodingKey {
            case check0
            case check1
        }
    
        /// 自定义解码方法,处理Bool值为1/0的情况
        public required init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            check0 = try container.decode(Bool.self, forKey: CodingKeys.check0)
            check1 = (try container.decode(Int.self, forKey: CodingKeys.check1) == 1) ? true : false
        }
    }
    

    解析:

    let data = sample4Json.data(using: .utf8)
    do {
        let status: Sample1 = try JSONDecoder().decode(Sample1.self, from: data!)
        print(status)
    } catch {
        print(error)
    }
    

    解析结果:

    (lldb) p status
    (CodableDemo.Sample) $R0 = 0x000060c000024c80 {
      check0 = true
      check1 = true
    }
    

    8、继承

    注意:继承的类使用codable解析,子类的属性无法正确赋值,通过自定义子类的解码方法可实现继承的类也能使用codable正确解析

    具体实现如下

    class

    class Dog: Codable {
        var name: String?
        var age: Int?
    }
    
    class HSQ: Dog {
        var IQ: Int?
    
        private enum CodingKeys: String, CodingKey {
            case IQ
        }
    
        public required init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            IQ = try container.decode(Int.self, forKey: CodingKeys.IQ)
            try super.init(from: decoder)
        }
    }
    

    解析

    let data = sample6Json.data(using: .utf8)
    do {
        let decoder = JSONDecoder()
        let x: HSQ = try decoder.decode(HSQ.self, from: data!)
    
        print(x)
    } catch {
        print(error)
    }
    

    解析结果:

    (lldb) p x
    (CodableDemo.HSQ) $R1 = 0x00006000000875d0 {
      CodableDemo.Dog = {
        name = "基金1"
        age = 2
      }
      IQ = -10
    }
    (lldb) 
    

    参考:

    https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types?language=objc

    https://benscheirman.com/2017/06/swift-json/

    https://www.jianshu.com/p/bdd9c012df15

    相关文章

      网友评论

        本文标题:Codable使用

        本文链接:https://www.haomeiwen.com/subject/ocwbxftx.html