Swift 从API调用和模型文件同时解码可编码结构

Swift 从API调用和模型文件同时解码可编码结构,swift,codable,jsondecoder,Swift,Codable,Jsondecoder,我目前正在从事一个项目,我正在调用一个Web服务,该服务返回一个JSON,我使用Codable进行解析,如下所示: struct User: Codable { var name: String var age: Int var detail: Detail } struct Detail: Codable { var id: Int var dob: Date } 我的结构: struct User: Codable { var name

我目前正在从事一个项目,我正在调用一个Web服务,该服务返回一个JSON,我使用Codable进行解析,如下所示:

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

struct Detail: Codable {
    var id: Int 
    var dob: Date 
}
我的结构:

struct User: Codable {
    var name: String
    var age: Int
}
API响应:

{姓名:罗米罗,年龄:27}

解码码:

let decoded = try! JSONDecoder().decode(User.self, from: data)
我们决定通过添加如下新字段来扩展用户信息:

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

struct Detail: Codable {
    var id: Int 
    var dob: Date 
}
但是,后端尚未开发,因此API响应仍然是可用的

{姓名:罗米罗,年龄:27}

有没有合适的方法只模拟var detail:detail部分,方法是从项目资源中匹配detail结构的detail-mock.json文件加载它,但同时保留对预先存在的用户部分的API调用

通过这样做,我将能够保持调用端点的所有逻辑,并通过调用

let decoded = try! JSONDecoder().decode(User.self, from: data)
此外,有没有一种方法可以在不改变API的json响应的情况下实现这一点?我不想手动将细节部分附加到je json响应中

注意:显然,用户结构就是一个例子,在我的项目中,这是一个复杂得多的结构

首先将detail设置为detail?类型,即

struct User: Codable {
    var name: String
    var age: Int
    var detail: Detail?
}
您可以为User和Detail创建两个单独的对象,并将Detail对象设置为User.Detail,即


您可以在用户上实现自定义解码,如下所示:

struct User: Codable {
    var name: String
    var age: Int
    var detail: Detail

    enum CodingKeys: CodingKey {
        case name, age, detail
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        age = try container.decode(Int.self, forKey: .age)
        if let detail = try container.decodeIfPresent(Detail.self, forKey: .detail) {
            self.detail = detail
        } else {
            let data = try Data(contentsOf: Bundle.main.url(forResource: "mockupDetail", withExtension: "json")!)
            self.detail = try JSONDecoder().decode(Detail.self, from: data)
        }
    }
}
注意init中的if语句。这就是我决定是从实际的json还是从模拟的json读取细节的地方


通过这种方式,您不需要将详细信息设置为可选,但需要手动解码其他属性。

是否要在创建用户对象os后手动添加详细信息的值?您可以执行类似于var detail:detail的操作?。可以为nil的键或json中可能不存在的键将它们标记为optional您的意思是var detail:detail?,然后解码文件中的细节并将其设置为my object?这意味着将var detail:detail设置为可选?