Ios CoreData-存储可转换对象的数组
我有一个实体具有可交易属性。它是一个自定义对象数组,Ios CoreData-存储可转换对象的数组,ios,swift,core-data,transformable,Ios,Swift,Core Data,Transformable,我有一个实体具有可交易属性。它是一个自定义对象数组,提醒,确认为NSSecureCoding @objc(Reminder) public class Reminder: NSObject, NSSecureCoding { public static var supportsSecureCoding: Bool = true public var date: Date public var isOn: Bool public in
提醒
,确认为NSSecureCoding
@objc(Reminder)
public class Reminder: NSObject, NSSecureCoding {
public static var supportsSecureCoding: Bool = true
public var date: Date
public var isOn: Bool
public init(date: Date, isOn: Bool) {
self.date = date
self.isOn = isOn
}
struct Keys {
static var date: String = "date"
static let isOn: String = "isOn"
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(date as NSDate,forKey: Keys.date)
aCoder.encode(isOn,forKey: Keys.isOn)
}
required public init?(coder aDecoder: NSCoder) {
guard let date = aDecoder.decodeObject(of: NSDate.self, forKey: Keys.date) as Date? else {
return nil
}
self.date = date
self.isOn = aDecoder.decodeBool(forKey: Keys.isOn)
}
}
下面的代码是我的
NSSecureUnarchiveFromDataTransformer
class ReminderDataTransformer: NSSecureUnarchiveFromDataTransformer {
override class func allowsReverseTransformation() -> Bool {
return true
}
override class func transformedValueClass() -> AnyClass {
return Reminder.self
}
override class var allowedTopLevelClasses: [AnyClass] {
return [Reminder.self]
}
override func transformedValue(_ value: Any?) -> Any? {
guard let data = value as? Data else {
fatalError("Wrong data type: value must be a Data object; received \(type(of: value))")
}
return super.transformedValue(data)
}
override func reverseTransformedValue(_ value: Any?) -> Any? {
guard let reminder = value as? [Reminder] else {
fatalError("Wrong data type: value must be a Reminder object; received \(type(of: value))")
}
return super.reverseTransformedValue(reminder)
}
}
extension NSValueTransformerName {
static let reminderToDataTransformer = NSValueTransformerName(rawValue: "ReminderToDataTransformer")
}
ValueTransformer.setValueTransformer(ReminderDataTransformer(), forName: .reminderToDataTransformer)
在初始化NSPersistantContainer之前,我已使用以下代码注册了
提醒DataTransformer
class ReminderDataTransformer: NSSecureUnarchiveFromDataTransformer {
override class func allowsReverseTransformation() -> Bool {
return true
}
override class func transformedValueClass() -> AnyClass {
return Reminder.self
}
override class var allowedTopLevelClasses: [AnyClass] {
return [Reminder.self]
}
override func transformedValue(_ value: Any?) -> Any? {
guard let data = value as? Data else {
fatalError("Wrong data type: value must be a Data object; received \(type(of: value))")
}
return super.transformedValue(data)
}
override func reverseTransformedValue(_ value: Any?) -> Any? {
guard let reminder = value as? [Reminder] else {
fatalError("Wrong data type: value must be a Reminder object; received \(type(of: value))")
}
return super.reverseTransformedValue(reminder)
}
}
extension NSValueTransformerName {
static let reminderToDataTransformer = NSValueTransformerName(rawValue: "ReminderToDataTransformer")
}
ValueTransformer.setValueTransformer(ReminderDataTransformer(), forName: .reminderToDataTransformer)
我在xCode的数据模型检查器中使用了
提醒器TodatTransformer
作为变压器
但由于在保存实体时发生以下错误,它无法工作
[error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x282ec0780> , <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x282ec0780> , <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
2020-12-31 21:44:09.300394+0100 ReminderApp[26406:6247995] [error] error: -executeRequest: encountered exception = <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
[error]错误:SQLCore dispatchRequest:异常处理请求:,在编码值时引发。用户信息为(空)
CoreData:错误:SQLCore dispatchRequest:异常处理请求:,在编码值时引发。用户信息为(空)
2020-12-31 21:44:09.300394+0100提醒应用[26406:6247995][错误]错误:-executeRequest:编码值时遇到异常=引发。使用userInfo=(null)
更新
也不例外。当第二次启动应用程序时,此错误将记录在控制台中
[error] fault: exception raised during multi-threaded fetch <shared NSSecureUnarchiveFromData transformer> threw while decoding a value. ({
NSUnderlyingError = "Error Domain=NSCocoaErrorDomain Code=4864 \"value for key 'root' was of unexpected class 'NSArray (0x1fa392238) [/System/Library/Frameworks/CoreFoundation.framework]'. Allowed classes are '{(\n \"Reminder (0x100fb6920) [/private/var/containers/Bundle/Application/306C3F0B-75AA-4A2D-A934-260B2EB63313/ReminderApp]\”\n)}’.\” UserInfo={NSDebugDescription=value for key 'root' was of unexpected class 'NSArray (0x1fa392238) [/System/Library/Frameworks/CoreFoundation.framework]'.
[error]错误:解码值时,在多线程获取期间引发异常。({
NSUnderlyingError=“Error Domain=nscocaerordomain Code=4864\”键“root”的值属于意外的类“NSArray(0x1fa39238)[/System/Library/Frameworks/CoreFoundation.framework]”。允许的类为“{(\n\”提醒(0x100fb6920)[/private/var/containers/Bundle/Application/306C3F0B-75AA-4A2D-A934-260B2EB63313/rementerapp]”“.\”UserInfo={NSDebugDescription=键“root”的值属于意外的类“NSArray(0x1fa39238)[/System/Library/Frameworks/CoreFoundation.framework]”。
如果我将代码更改为存储
提醒
而不是[提醒]
,我想我无法正确编码/解码提醒的数组,因为它可以正常工作
为了清楚起见,我可以存储提醒
,但不能存储[提醒]
如何将
[提醒]
存储为可转换的
如果要取消归档数组,必须将NSArray
添加到顶级类,这就是我理解错误消息的方式
override class var allowedTopLevelClasses: [AnyClass] {
return [NSArray.self, Reminder.self]
}
顺便说一下,代替一个可变形的考虑将数组编码为JSON并将其保存为一个简单的字符串。转换可以由计算的属性执行。
该类可以是一个代码少得多的结构
public struct Reminder : Codable {
public var date: Date
public var isOn: Bool
}
在NSManagedObject
子类中创建一个String
属性
@NSManaged public var cdReminders : String
和计算属性
var reminders : [Reminder] {
get {
return (try? JSONDecoder().decode([Reminder].self, from: Data(cdReminders.utf8))) ?? []
}
set {
do {
let reminderData = try JSONEncoder().encode(newValue)
cdReminders = String(data: reminderData, encoding:.utf8)!
} catch { cdReminders = "" }
}
}
添加到@vadian的答案中,如果您希望包含父数据转换器中允许的顶级类,请尝试
override static var allowedTopLevelClasses: [AnyClass] {
var allowed = super.allowedTopLevelClasses
allowed(contentsOf: [Reminder.self])
return allowed
}
当异常发生时,你能设置断点并查看数据吗?@RahulIyer我更新了我的问题。阅读更新部分。非常感谢。谢谢!这帮了大忙。