简体   繁体   English

CoreData - 存储一组可转换对象

[英]CoreData - Store an array of Tranformable objects

I have an entity that has a traformable property.我有一个具有可变形属性的实体。 It is an array of custom object, Reminder that confirms to NSSecureCoding .它是一个自定义 object 的数组, Reminder 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)
    }
}

And the following code is my NSSecureUnarchiveFromDataTransformer .以下代码是我的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")
}

I have registered ReminderDataTransformer using the following code before initializing NSPersistantContainer .在初始化NSPersistantContainer之前,我已经使用以下代码注册了ReminderDataTransformer

ValueTransformer.setValueTransformer(ReminderDataTransformer(), forName: .reminderToDataTransformer)

I have used ReminderToDataTransformer as Transformer in xCode's Data Model Inspector.我在 xCode 的 Data Model Inspector 中使用了ReminderToDataTransformer作为 Transformer。


But it does not work because of the following error that occurs when saving entities.但它不起作用,因为保存实体时出现以下错误。

 [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)

Update更新

There is no exception.也不例外。 When launching the app for the second time, this error is logged in console.第二次启动应用程序时,控制台会记录此错误。

[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]'. 

I guess I am unable to correctly encode / decode Reminder's array as It works if I change the code to store Reminder instead of [Reminder] .我想我无法正确编码/解码 Reminder 的数组,因为如果我将代码更改为存储Reminder而不是[Reminder] ,它就可以工作。

Just to be clear, I can store Reminder , but not [Reminder] .为了清楚起见,我可以存储Reminder ,但不能存储[Reminder]


How to store [Reminder] as Transformable ?如何将[Reminder]存储为可Transformable的?


If you are going to unarchive an array you have to add NSArray to the top level classes, this is how I understand the error message如果要取消归档数组,则必须将NSArray添加到顶级类,这就是我理解错误消息的方式

override class var allowedTopLevelClasses: [AnyClass] {
    return [NSArray.self, Reminder.self]
}

By the way, instead of a transformable consider to encode the array to JSON and save it as a simple String.顺便说一句,而不是可转换的考虑将数组编码为 JSON 并将其保存为简单的字符串。 The conversion can be performed by a computed property.转换可以由计算属性执行。

The class can be a struct with dramatically less code class 可以是一个代码少得多的结构

public struct Reminder : Codable {
    public var date: Date
    public var isOn: Bool
}

In the NSManagedObject subclass create a String AttributeNSManagedObject子类中创建一个String属性

@NSManaged public var cdReminders : String

and a computed property和一个计算属性

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 = "" }
    }
}

Adding to @vadian's answer, if you want to include the allowed top level classes from the parent data transformer, try添加到@vadian 的答案,如果您想包含父数据转换器中允许的顶级类,请尝试

override static var allowedTopLevelClasses: [AnyClass] {
    var allowed = super.allowedTopLevelClasses
    allowed(contentsOf: [Reminder.self])
    
    return allowed
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM