Codable Tips

282 阅读1分钟

json解析 技巧

流程图

利用Codable解析JSON

let json = """
{
    "name": "Paul",
    "age": 14
}
          """

let data = Data(json.utf8)

如果JSON键值与swift属性名称相同,因为编译器已经处理了关系映射,可以直接解析

struct User: Codable {
    var name: String
    var age: Int
}

let decoder = JSONDecoder()
do {
    let decoded = try decoder.decode(User.self, from: data)
    print(decoded[0].name)
} catch {
    print("Failed to decode JSON")
}
 

如果JSON键与Swift属性完全不同,则可以使用CodingKeys枚举来映射它们,例如:

struct User2: Codable {
    var username: String
    var age: Int
    
    enum CodingKeys: String, CodingKey {
        case username = "name"
        case age
    }
}

do {
    let decoded = try decoder.decode(User2.self, from: data)
    print(decoded[0].name)
} catch {
    print("Failed to decode JSON")
}

JSON嵌套层级的处理,如下JSON:

let json2 = """
{
    "latitude": 102.11,
    
    "longitude": 23.01,
    
    "additional": 
     { 
         "elevation": 1000
     }
}
"""
let data2 = Data(json.utf8)

因为JSON包含不同层级,如何利用Codable将json2用下面这个model解析呢

struct Coordinate: Codable {
    var latitude: Double
    var longitude: Double
    var elevation: Double
}

由于elevation与latitude、longitude不在同一层级

extension Coordinate {

    enum CodingKeys: String, CodingKey {
        case latitude
        case longitude
        case additional
    }
    
    enum AdditionalKeys: String, CodingKey {
        case elevation
    }

}
let decoder = JSONDecoder.init()

let container = try decoder.container(keyedBy: CodingKeys.self)
latitude = try values.decode(Double.self, forKey: .latitude)
longitude = try values.decode(Double.self, forKey: .longitude)

利用嵌套方法去读取下一层级的数据

container.nestedContainer(keyedBy: AdditionalKeys.self, forKey: .additional)


let additional = try container.nestedContainer(keyedBy: AdditionalKeys.self, forKey: .additional)
elevation = try additionalInfo.decode(Double.self, forKey: .elevation)

如何解析下面这种JSON

let json5 = """
[
  "A string",
  [
    "A string",
    "A string",
    "A string",
    "A string",
  ]
]
""".data(using: .utf8)!

利用 unkeyedContainer解析这种无Key的json

struct Model: Decodable {
    let str: String
    let array: [String]
   
    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        str = try container.decode(String.self)
        array = try container.decode([String].self)
    }
}

let ut = try JSONDecoder.init().decode(Model.self, from: json5)
print(ut)
// 输出
Model(str: "A string", array: ["A string", "A string", "A string", "A string"])

利用SingleValueContainer解析单个值

let json4 = "123".data(using: .utf8)!

struct Number: Codable {
    let value: Int
    init(value: Int) {
        self.value = value
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let v = try container.decode(Int.self)
        self.init(value: v)
    }
}

let decoder = JSONDecoder()
let d = try decoder.decode(Number.self, from: json4)
print(d) //输出:Number(value: 123)

Codable奇思妙想

Codable: Tips and Tricks

Codable详解