Swift - 利用Codable进行JSON解析

@Daniate  May 7, 2022

针对常见的几种情况,进行总结。

本文首发于Daniate的个人网站,文章链接:https://daniate.com/archives/329/

层次结构嵌套

模型与JSON层次结构对应时

JSON

{
    "geometry": {
        "type": "Point",
        "coordinates": [
            -97.089200000000005,
            39.745600000000003
        ]
    }
}

模型:

struct Entity: Codable {
    struct Geometry: Codable {
        var type: String
        var coordinates: [Double]
    }
    var geometry: Geometry
}

解析:

let jsonData = jsonText.data(using: .utf8)!
        
let decoder = JSONDecoder()
do {
    let entity = try decoder.decode(Entity.self, from: jsonData)
} catch {}

模型与JSON层次结构不对应时

JSON

{
    "geometry": {
        "type": "Point",
        "coordinates": [
            -97.089200000000005,
            39.745600000000003
        ]
    }
}

模型:

struct Entity: Codable {
    var type: String
    var coords: [Double]
}

添加新的模型及相关的extension

struct EntityWrapper: Codable {
    struct Geometry: Codable {
        var type: String
        var coordinates: [Double]
    }
    var geometry: Geometry
}

extension EntityWrapper {
    var entity: Entity {
        Entity(
            type: geometry.type,
            coords: geometry.coordinates
        )
    }
}

解析:

let jsonData = jsonText.data(using: .utf8)!
        
let decoder = JSONDecoder()
do {
    let wrapper = try decoder.decode(EntityWrapper.self, from: jsonData)
    let entity = wrapper.entity
    print(entity)
} catch {}

不同格式的日期

JSON

{
    "birthday": "1908-07-16",
    "deathday": "1993/10/23"
}

模型:

struct Entity: Codable {
    var birthday: Date
    var deathday: Date
}

解析:

let jsonData = jsonText.data(using: .utf8)!

let decoder = JSONDecoder()
// 自定义日期解码策略
decoder.dateDecodingStrategy = .custom({ dec in
    let container = try dec.singleValueContainer()
    let text = try container.decode(String.self)
    
    let df = DateFormatter()
    
    df.dateFormat = "yyyy-MM-dd"
    if let date = df.date(from: text) {
        return date
    }
    
    df.dateFormat = "yyyy/MM/dd"
    if let date = df.date(from: text) {
        return date
    }
    
    return Date()
})
do {
    let entity = try decoder.decode(Entity.self, from: jsonData)
    print(entity)
} catch {}

Key、property使用不同的命名规则

指的是JSON与模型,一个使用下划线命名法,另一个使用驼峰命名法

JSON

{
    "full_name": "Bill Gates",
    "country": "USA"
}

模型:

struct Entity: Codable {
    var fullName: String
    var country: String
}

解析:

let jsonData = jsonText.data(using: .utf8)!

let decoder = JSONDecoder()
// 下划线命名法 ----> 驼峰命名法
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
    let entity = try decoder.decode(Entity.self, from: jsonData)
    print(entity)
} catch {}

映射不同的Key和property

JSON

{
     "type": "Point",
     "coordinates": [
         -97.089200000000005,
         39.745600000000003
     ]
}

模型:

struct Entity: Codable {
    var type: String
    var coords: [Double]
    
    // 建立映射关系
    enum CodingKeys: String, CodingKey {
        case type
        case coords = "coordinates"
    }
}

解析:

let jsonData = jsonText.data(using: .utf8)!

let decoder = JSONDecoder()
do {
    let entity = try decoder.decode(Entity.self, from: jsonData)
    print(entity)
} catch {}

知识共享许可协议
本作品由Daniate采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。


评论已关闭