Swift 使用 Codable 解析 JSON

2019-03-20  本文已影响0人  MonkeyBread

示例1:

let jsonData: Data = """
{ 
  "name": "MonkeyBread",
  "address": "China",
  "email": "12345@gamil.com",
} 
""".data(using: .utf8)!
struct User: Codable {
    let name: String
    let address: String
    let email: String
}
let user = try? JSONDecoder().decode(User.self, from: jsonData)

JSON 与 Model 完全一致,这是最基础的 JSON 解析。

示例2:

let jsonData: Data = """
{
  "name": "MonkeyBread",
  "email": "12345@gamil.com",
  "addr": {
    "country": "China",
    "city": "Beijing",
    "lat": "123",
    "lng": "456",
    }
}
""".data(using: .utf8)!
struct Address: Codable {
    let country: String
    let city: String
    let latitude: String
    let longitude: String
}

struct User: Codable {
    let userName: String
    let email: String
    let address: Address
}
struct Address: Codable {
    let country: String
    let city: String
    let latitude: String
    let longitude: String

    private enum CodingKeys: String, CodingKey {
        case country
        case city
        case latitude = "lat"
        case longitude = "lng"
    }
}

struct User: Codable {
    let userName: String
    let email: String
    let address: Address

    private enum CodingKeys: String, CodingKey {
        case userName = "name"
        case email
        case address = "addr"
    }
}

let user = try? JSONDecoder().decode(User.self, from: jsonData)

JSON 与 Model 不一致的情况,可通过 CodingKeys 枚举对应,多层嵌套的情况也同样适用。
需要注意的是:如果重写 CodingKeys enum 需要包含 Model 中所有属性

示例3:

let jsonData: Data = """
{
"name": "MonkeyBread",
"email": "12345@gamil.com",
"addr": {
    "country": "China",
    "city": "Beijing",
    "lat": "123",
    "lng": "456"
    }
}
""".data(using: .utf8)!
struct User: Codable {
    let userName: String
    let email: String

    let country: String
    let city: String
    let latitude: String
    let longitude: String
}
struct User: Codable {
    var userName: String = ""
    var email: String = ""

    var country: String = ""
    var city: String = ""
    var latitude: String = ""
    var longitude: String = ""

    private enum UserKeys: String, CodingKey {
        case userName = "name"
        case email
        case addr
    }

    private enum AddressKeys: String, CodingKey {
        case country
        case city
        case latitude = "lat"
        case longitude = "lng"
    }

    init(from decoder: Decoder) throws {

        if let userContainer = try? decoder.container(keyedBy: UserKeys.self) {
            self.userName = try userContainer.decode(String.self, forKey: .userName)
            self.email = try userContainer.decode(String.self, forKey: .email)

            if let addressContainer = try? userContainer.nestedContainer(keyedBy: AddressKeys.self, forKey: .addr) {
                self.country = try addressContainer.decode(String.self, forKey: .country)
                self.city = try addressContainer.decode(String.self, forKey: .city)
                self.latitude = try addressContainer.decode(String.self, forKey: .latitude)
                self.longitude = try addressContainer.decode(String.self, forKey: .longitude)
            }
        }
    }
}

if let user = try? JSONDecoder().decode(User.self, from: jsonData) {
    print(user.userName)
    print(user.email)
    print(user.country)
    print(user.latitude)
    print(user)
}

示例中的 addr 参数包含了地理位置信息,一般情况都会按照 示例2 的方式解析,但如果项目中仅用到了 country 参数,创建 Address 类来接收参数就显得很累赘了,此示例就是将 addr 参数与 User 参数合并成了一层,省去了 Address 类。

上一篇下一篇

猜你喜欢

热点阅读