为SwiftUI类添加@Observable后出现解码警告及JSON加载失败问题
解决@Observable与Codable冲突导致的JSON解码问题
问题根源
给遵循Codable的类添加@Observable修饰符后,Swift为Observable生成的合成逻辑会干扰Codable的自动解码合成。编译器误判属性存在不可覆盖的初始值,进而触发警告并导致JSON加载失败。
解决方案:手动实现Codable方法
放弃依赖自动合成的Codable实现,手动编写init(from decoder:)和encode(to:)方法,明确控制每个属性的解码/编码流程,规避Observable合成逻辑的干扰。
示例:Address类修改
@Observable class Address: Codable { var street: String var city: String var zipCode: String // 定义编码/解码键 enum CodingKeys: String, CodingKey { case street, city, zipCode } // 手动实现解码初始化器 required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) street = try container.decode(String.self, forKey: .street) city = try container.decode(String.self, forKey: .city) zipCode = try container.decode(String.self, forKey: .zipCode) } // 手动实现编码方法 func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(street, forKey: .street) try container.encode(city, forKey: .city) try container.encode(zipCode, forKey: .zipCode) } }
嵌套类处理(如Programmer类)
如果程序员模型嵌套了Address这类Observable类,同样需要手动实现Codable方法:
@Observable class Programmer: Codable { var name: String var address: Address enum CodingKeys: String, CodingKey { case name, address } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) name = try container.decode(String.self, forKey: .name) // 手动解码嵌套的Address对象 address = try container.decode(Address.self, forKey: .address) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(name, forKey: .name) try container.encode(address, forKey: .address) } }
额外检查项
- 确认JSON文件的键名与
CodingKeys完全一致,避免拼写错误 - 验证JSON加载逻辑,确保文件路径正确、数据读取正常:
func loadProgrammers() -> [Programmer] { guard let url = Bundle.main.url(forResource: "programmers", withExtension: "json"), let data = try? Data(contentsOf: url), let programmers = try? JSONDecoder().decode([Programmer].self, from: data) else { return [] } return programmers }
内容的提问来源于stack exchange,提问作者Louie88
相关产品推荐
相关产品推荐

