swift学习

Codable使用

2018-02-28  本文已影响0人  kawa007

准备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

上一篇下一篇

猜你喜欢

热点阅读