Swift Codable解码完成后执行初始化逻辑的实现方案咨询
哈哈,这个问题我之前也遇到过!手动写init(from:)几千行简直是噩梦,给你几个不用手动实现全量解码的方案,完美解决你的需求:
方案一:用Lazy属性延迟处理(最简单)
如果只是少数属性需要做初始化逻辑,这个方案最省心,完全依赖Codable的自动合成能力:
struct MyStruct: Codable { let id: Int // 用私有存储属性保存JSON解码出来的原始name private let originalName: String // 第一次访问name时,自动拼接id和原始名称 lazy var name: String = "\(id) \(originalName)" }
解码时编译器会自动给id和originalName赋值,只有当你第一次调用name的时候,才会执行拼接逻辑,完全不用干涉解码流程。
方案二:内部编码结构体中转(适合复杂场景/大量属性)
如果你的结构体有上千个属性,或者需要处理的逻辑比较复杂,这个方案绝对是救星:
struct MyStruct: Codable { let id: Int var name: String // 这里可以放你所有的上千个属性 // 内部定义一个和外部结构完全一致的代理结构体,让它自动生成Codable逻辑 private struct CodingProxy: Codable { let id: Int let name: String // 同步复制外部结构体的所有属性,编译器会自动帮你生成解码代码 } // 实现自定义的解码初始化器,先解码代理结构体,再处理逻辑 init(from decoder: Decoder) throws { // 自动解码所有属性到代理对象 let proxy = try CodingProxy(from: decoder) // 把代理对象的属性赋值给当前结构体 self.id = proxy.id self.name = "\(proxy.id) \(proxy.name)" // 这里可以添加任何你需要的初始化逻辑,比如其他属性的处理 } // 编码逻辑直接复用当前结构体的属性即可 func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(id, forKey: .id) try container.encode(name, forKey: .name) } private enum CodingKeys: String, CodingKey { case id, name } }
核心思路是让内部的CodingProxy自动合成所有属性的解码代码,你只需要在外部的初始化器里完成一次属性赋值,同时执行自定义逻辑。就算有上千个属性,也只需要把它们同步到CodingProxy里,完全不用手动写解码逻辑。
方案三:属性观察者(谨慎使用)
这个方案依赖属性的didSet观察者,但要注意解码时的属性赋值顺序可能不确定,所以只适合逻辑不依赖其他属性顺序的场景:
struct MyStruct: Codable { let id: Int var name: String { didSet { setupOnce() } } // 标记是否已经执行过初始化逻辑,避免重复执行 private var isSetupDone = false private mutating func setupOnce() { guard !isSetupDone else { return } name = "\(id) \(name)" isSetupDone = true } }
当name被解码赋值时,会触发didSet调用setupOnce执行逻辑,但如果解码时id还没被赋值,就会出问题,所以这个方案不如前两个可靠。
总结一下:如果只是个别属性处理,选方案一;如果是大量属性或复杂逻辑,选方案二;方案三尽量谨慎使用。
内容的提问来源于stack exchange,提问作者Darko
相关产品推荐
相关产品推荐

