SwiftData存储含CodingKeys枚举的Struct报错,求非重复结构体方案
问题场景
我从网络下载公交服务信息,用带CodingKeys的Service结构体做JSON解码,这部分功能正常:
struct Service: Codable { var serviceNo: String // 其他属性 enum CodingKeys: String, CodingKey { case serviceNo = "serviceNo" // 其他需解码的JSON属性 } }
随后创建@Model类存储服务与站点的组合信息:
@Model class FrequentService { var service: Service var stop: BusStop init(){ /* 初始化逻辑 */ } }
用@Query获取数据展示时,触发CoreData错误:
Row (pk = 1) for entity 'FrequentService' is missing mandatory text data for property 'serviceNo'
测试确认插入FrequentService时触发错误,且service.serviceNo确实有有效值。移除Service中的CodingKeys枚举后,SwiftData恢复正常,但我需要保留CodingKeys完成JSON编解码,不想创建重复的结构体。
解决方法
方法1:移除CodingKeys中冗余的同名映射
默认情况下,Codable会自动映射属性名与JSON键名一致的字段,不需要显式在CodingKeys中声明。比如serviceNo = "serviceNo"这种完全冗余的case可以直接删除,只保留那些JSON键与属性名不同的映射:
struct Service: Codable { var serviceNo: String // 示例:JSON键为"bus_name",属性名为busName,需要显式映射 var busName: String enum CodingKeys: String, CodingKey { case busName = "bus_name" // 其他需要不同名映射的属性 } }
这样既保留了JSON编解码所需的自定义映射,又不会干扰SwiftData对结构体属性的识别。
方法2:给结构体属性添加@Attribute注解
如果必须保留所有CodingKeys(包括同名的),可以给Service的属性添加@Attribute注解,明确告诉SwiftData该属性需要被持久化:
import SwiftData struct Service: Codable { @Attribute var serviceNo: String // 其他属性 enum CodingKeys: String, CodingKey { case serviceNo = "serviceNo" // 其他需解码的JSON属性 } }
这个注解会强制SwiftData识别并存储该属性,避免因为CodingKeys的存在而忽略它。
方法3:让Service遵循PersistentModel(进阶)
如果Service本身需要作为独立的持久化对象(而非嵌入式属性),可以让它遵循PersistentModel协议,同时保留Codable实现:
import SwiftData struct Service: PersistentModel, Codable { var serviceNo: String // 其他属性 enum CodingKeys: String, CodingKey { case serviceNo = "serviceNo" // 其他需解码的JSON属性 } }
不过这种方式需要确保结构体的所有属性都能被SwiftData正确持久化,适合需要单独管理Service数据的场景。
总结
不需要创建重复的结构体,通过以上任意一种方法,就能让带CodingKeys的Service结构体同时兼容JSON编解码和SwiftData存储。
内容的提问来源于stack exchange,提问作者user16405656

