如何为[[Int?]]与[[String?]]实现Core Data Transformable类型支持
报错原因
你遇到的报错本质是:NSKeyedUnarchiver的unarchivedObject(ofClass:from:)方法要求解析的类型必须遵守NSCoding协议,而Swift原生的二维可选数组([[Int32?]]、[[String?]])、自定义TileModel结构体都默认不遵守NSCoding,所以无法直接用基于NSCoding的转换器实现序列化。
解决方案
因为你所有需要持久化的类型都已经遵守Codable协议,完全可以抛弃NSCoding那套逻辑,直接基于JSONEncoder/JSONDecoder实现自定义转换器,步骤如下:
- 实现通用泛型Codable转换器
不用单独写三个重复的转换器,直接写一个通用的泛型类复用逻辑:
class CodableValueTransformer<T: Codable>: ValueTransformer { override class func transformedValueClass() -> AnyClass { return NSData.self } override class func allowsReverseTransformation() -> Bool { return true } override func transformedValue(_ value: Any?) -> Any? { guard let value = value as? T else { return nil } do { return try JSONEncoder().encode(value) } catch { print("序列化失败: \(error)") return nil } } override func reverseTransformedValue(_ value: Any?) -> Any? { guard let data = value as? Data else { return nil } do { return try JSONDecoder().decode(T.self, from: data) } catch { print("反序列化失败: \(error)") return nil } } } // 扩展Transformer名称,方便注册调用 extension NSValueTransformerName { static let lettersTransformer = NSValueTransformerName(rawValue: "LettersTransformer") static let valuesTransformer = NSValueTransformerName(rawValue: "ValuesTransformer") static let tilesTransformer = NSValueTransformerName(rawValue: "TilesTransformer") }
- 注册对应类型的转换器
在Persistence.swift的初始化方法中,注册三个对应类型的转换器实例:
init(inMemory: Bool = false) { // 注册三个对应类型的转换器 ValueTransformer.setValueTransformer( CodableValueTransformer<[[String?]]>(), forName: .lettersTransformer ) ValueTransformer.setValueTransformer( CodableValueTransformer<[[Int32?]]>(), forName: .valuesTransformer ) ValueTransformer.setValueTransformer( CodableValueTransformer<[TileModel]?>(), forName: .tilesTransformer ) container = NSPersistentContainer(name: "TransApp") // 原有持久化容器初始化逻辑保持不变 }
- 配置Core Data实体属性
打开你的.xcdatamodeld数据模型文件,对三个属性做如下配置:
- 类型选择
Transformable Transformer栏填写你注册的转换器名称,比如letters属性就填LettersTransformerCustom Class栏填写对应Swift类型,比如letters属性就填[[String?]]
配置完成后清理项目重新编译即可解决报错。
可选替代方案
如果你不想用Transformable类型,也可以直接把三个属性在Core Data中设置为Binary Data类型,在toEntity方法和实体转模型的方法中自己实现序列化/反序列化逻辑,效果和自定义转换器完全一致。
内容的提问来源于stack exchange,提问作者Alexander Farber
相关产品推荐
相关产品推荐

