Swift中InstrumentsSet扩展的嵌套Track结构体单独加载JSON失败如何解决
问题结论
首先明确:你完全可以单独加载定义在扩展内的InstrumentsSet.Track结构体,当前的代码结构本身支持这种操作,解码失败是其他细节问题导致的。
核心原因排查&解决方案
- 首要问题:
Track缺少Identifiable协议要求的id属性适配
你声明了Track遵守Identifiable协议,该协议强制要求存在id属性。默认情况下Decodable会自动合成解码逻辑,尝试从JSON中读取id字段,而你提供的Track JSON中没有该字段,导致解码失败。
解决方法:手动指定解码字段,排除id,并给id设置默认值:
extension InstrumentsSet { struct Track: Identifiable, Decodable { // 自动生成唯一id,无需从JSON解码 let id = UUID() let instrumentType: InstrumentType let startType: StartType // 手动指定需要解码的字段,不包含id enum CodingKeys: String, CodingKey { case instrumentType, startType } // 原有withJSON方法保持不变即可 } }
同理你之前能成功解码InstrumentsSet,大概率是已经对InstrumentsSet的id做了类似适配,只需给Track做相同处理即可。
- 次常见问题:自定义枚举未适配
Decodable
检查InstrumentType和StartType两个自定义类型(通常为枚举),确保:
- 明确遵守
Decodable协议,比如字符串枚举声明为:
enum InstrumentType: String, Decodable { case exsSampler, audioBuffer } enum StartType: String, Decodable { case trigger, global }
- 枚举的case取值和JSON中的字符串完全一致,大小写、拼写都不能有差异。
- 调试技巧:不要吞掉解码错误
你当前使用try?会直接忽略所有错误信息,无法定位具体问题,把解码逻辑改成do-catch打印错误即可快速定位根因:
static func withJSON(_ fileName: String) -> InstrumentsSet.Track? { guard let url = Bundle.main.url(forResource: fileName, withExtension: "json", subdirectory: "Sets") else { return nil } guard let data = try? Data(contentsOf: url) else { return nil } do { return try JSONDecoder().decode(InstrumentsSet.Track.self, from: data) } catch { // 控制台会输出精准的错误原因,比如缺字段、枚举值不匹配等 print("解码失败:\(error)") return nil } }
内容的提问来源于stack exchange,提问作者Frans-Jan Wind
相关产品推荐
相关产品推荐

