Swift中使用var替代let时JSONDecoder解码失败问题
Swift Codable解码异常:var属性失败,let属性正常
以下是相关代码:
import Foundation func load<T: Codable>() -> T? { let data: Data let fileUrl = Bundle.main.url(forResource: "main.json", withExtension: nil) do { data = try Data(contentsOf: fileUrl!) } catch { fatalError("error getting data: \(error.localizedDescription)") } do { return try JSONDecoder().decode(T.self, from: data) } catch { fatalError("error decoding: \(error.localizedDescription)") } } @Observable class Mordor: Codable { var id: Int init(id: Int) { self.id = id } }
在其他视图中调用解码逻辑:
let m: Mordor? = load()
此时抛出错误:
error decoding: The data couldn’t be read because it is missing.
但将Mordor类中的var id: Int修改为let id: Int后,解码功能恢复正常。
问题原因
- 当使用
@Observable修饰类时,Swift会为所有var属性生成带观察逻辑的访问器,这会破坏Codable自动合成所需的标准存储属性结构。 Codable自动合成的解码逻辑依赖于属性的默认存储行为,@Observable对var的修改导致解码器无法正确识别和初始化属性,进而抛出数据缺失的错误。- 对于
let属性,由于其不可变性,@Observable不会生成额外的访问器,Codable可以正常合成解码逻辑。
解决方案
方案1:使用let声明属性(适合不需要后续修改的场景)
@Observable class Mordor: Codable { let id: Int init(id: Int) { self.id = id } }
方案2:手动实现Codable协议(适合需要属性可变的场景)
@Observable class Mordor: Codable { var id: Int init(id: Int) { self.id = id } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decode(Int.self, forKey: .id) } enum CodingKeys: String, CodingKey { case id } }
内容的提问来源于stack exchange,提问作者sumit kumar Pradhan
相关产品推荐
相关产品推荐

