You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 23:46:19