[英]CoreData - Store an array of Tranformable objects
我有一個具有可變形屬性的實體。 它是一個自定義 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)
}
}
以下代碼是我的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")
}
在初始化NSPersistantContainer
之前,我已經使用以下代碼注冊了ReminderDataTransformer
。
ValueTransformer.setValueTransformer(ReminderDataTransformer(), forName: .reminderToDataTransformer)
我在 xCode 的 Data Model Inspector 中使用了ReminderToDataTransformer
作為 Transformer。
但它不起作用,因為保存實體時出現以下錯誤。
[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] 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]'.
我想我無法正確編碼/解碼 Reminder 的數組,因為如果我將代碼更改為存儲Reminder
而不是[Reminder]
,它就可以工作。
為了清楚起見,我可以存儲Reminder
,但不能存儲[Reminder]
。
如何將[Reminder]
存儲為可Transformable
的?
如果要取消歸檔數組,則必須將NSArray
添加到頂級類,這就是我理解錯誤消息的方式
override class var allowedTopLevelClasses: [AnyClass] {
return [NSArray.self, Reminder.self]
}
順便說一句,而不是可轉換的考慮將數組編碼為 JSON 並將其保存為簡單的字符串。 轉換可以由計算屬性執行。
class 可以是一個代碼少得多的結構
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
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.