如何将CoreData属性存储为(Codable) Data而非(NSCoding) Transformables?
把结构体数组打包存入Core Data单属性的方案
这个需求我太有共鸣了——让Core Data单独管理每个结构体对象不仅麻烦,还会带来额外的性能开销,把整个数组打包成单个属性存储确实是更优的选择。这里给你两种可行方案,按需选择:
方案一:自定义NSValueTransformer(完全可控)
如果需要对序列化/反序列化流程有100%的控制权,自定义NSValueTransformer是最稳妥的方式:
- 继承
NSValueTransformer,实现transformedValue(_:)方法把结构体数组转成可存储的格式(比如Data或plist) - 实现
reverseTransformedValue(_:)方法把存储的格式转回结构体数组 - 在Core Data模型编辑器里,给目标属性设置这个自定义转换器,同时把属性类型设为对应可存储的类型(比如Binary Data)
这种方式适合有特殊序列化需求的场景,但需要写不少模板代码。
方案二:Swift 4+ Codable序列化(快速实现)
如果想减少工作量,Swift 4引入的Codable协议绝对是最佳选择,几步就能搞定:
- 让结构体遵循Codable:只要你的结构体所有属性都支持Codable(比如String、Int、Double这些基础类型,或者其他遵循Codable的自定义类型),直接加协议就行,不需要额外代码:
struct YourStruct: Codable { var name: String var value: Int // 其他属性... }
- 在Core Data实体里添加Data属性:打开Core Data模型,给目标实体新增一个类型为
Binary Data的属性,比如命名为structsData - 封装成计算属性:在你的NSManagedObject子类里,添加一个计算属性来封装这个Data属性,自动处理序列化和反序列化:
@objc(YourEntity) public class YourEntity: NSManagedObject { @NSManaged public var structsData: Data? // 封装的计算属性,对外直接用结构体数组 var structArray: [YourStruct] { get { guard let data = structsData else { return [] } return try? JSONDecoder().decode([YourStruct].self, from: data) ?? [] } set { structsData = try? JSONEncoder().encode(newValue) } } }
额外提示
- 如果你觉得JSON序列化性能不够,也可以用
PropertyListEncoder和PropertyListDecoder代替,序列化后的Data体积更小,适合原生类型居多的结构体 - 如果结构体里有非Codable的属性(比如UIImage),可以自定义
init(from decoder: Decoder)和encode(to encoder: Encoder)方法来处理特殊字段
内容的提问来源于stack exchange,提问作者wardw
相关产品推荐
相关产品推荐

