【问题标题】:Secure Coding Measurement Classes in Core Data, NSValueTransformers核心数据中的安全编码测量类,NSValueTransformers
【发布时间】:2021-07-10 19:30:51
【问题描述】:

我有一个大量使用 Measurements 的应用。它是用 SwiftUI/iOS 14 编写的。我将数据保存在 Core Data 数据库中。该应用程序运行良好,直到我尝试实施安全编码。我制作了一个示例应用程序来剥离除基础之外的所有内容。它基于 Xcode 的默认 Core Data 应用程序,几乎没有更改。同样,我可以很好地保存我的测量结果,直到我尝试使用安全编码。

xddatamodel 以及错误如下:

我正在为实体使用手动代码生成器,它看起来像这样:

extension Item {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Item> {
        return NSFetchRequest<Item>(entityName: "Item")
    }

    @NSManaged public var timestamp_: Date?
    @NSManaged private var notes_: String?
    @NSManaged private var length_: Measurement<UnitLength>?

    public var timestamp: Date {
        get { timestamp_ ?? Date(timeIntervalSince1970: 0) }
        set { timestamp_ = newValue }
    }

    public var notes: String {
        get { notes_ ?? "Add Notes Here..." }
        set { notes_ = newValue }
    }

    public var length: Measurement<UnitLength> {
        get { length_ ?? Measurement(value: 0, unit: UnitLength.meters) }
        set { length_ = newValue }
    }

}

虽然我尝试在不同的地方注册 ValueTransformer,但我目前在 @main:

@main
struct Core_Data_TestApp: App {
    let persistenceController: PersistenceController
    
    init() {
        UnitLengthValueTransformer.register()
        persistenceController = PersistenceController.shared
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
        }
    }
}

我的 ValueTransformer 如下所示:

@objc(UnitLengthValueTransformer)
final class UnitLengthValueTransformer: NSSecureUnarchiveFromDataTransformer {
    static let name = NSValueTransformerName(rawValue: String(describing: UnitLengthValueTransformer.self))
    override static var allowedTopLevelClasses: [AnyClass] {
        return [UnitLength.self]
    }
    
    public static func register() {
        let transformer = UnitLengthValueTransformer()
        ValueTransformer.setValueTransformer(transformer, forName: name)
    }
}

据我所知存在分歧,UnitLength 的类头是:

open class UnitLength : Dimension, NSSecureCoding 

所以它确实符合 NSSecureCoding。

我使用了以下参考资料:

Transformable and NSKeyedUnarchiveFromData

CoreData Transformable and NSSecureCoding in iOS 13+

ValueTransformer in Core Data explained: Storing absolute URLs

我仍然遇到同样的错误:

Fatal error: Unresolved error Error Domain=NSCocoaErrorDomain Code=134060 "A Core Data error occurred.", [:]: file Core_Data_Test/ContentView.swift, line 57

我无法弄清楚我做错了什么导致崩溃。

【问题讨论】:

  • 测量不符合 NSSecureCoding
  • @LeoDabus 我检查了,并且 NSMeasurement 确实符合。关于如何将其保存为 NSMeasurement 的任何想法?
  • NSMeasurement 有,但Measurement 没有

标签: ios swift core-data swiftui


【解决方案1】:

感谢@LeoDabus,我终于能够敲定这一点。关键是将 Swift Measurements 转换为 NSMeasurement 并在 Core Data 中使用 NSMeasurement。您需要将自定义类设置为NSMeasurement。您的转换器将是一个自定义值转换器。我打电话给我的NSMeasurementValueTransformer。您的 .xcdatamodeld 将如下所示:

我将自定义值转换器定义为:

@objc(NSMeasurementValueTransformer)
final class NSMeasurementValueTransformer: NSSecureUnarchiveFromDataTransformer {
    static let name = NSValueTransformerName(rawValue: String(describing: NSMeasurementValueTransformer.self))
    override static var allowedTopLevelClasses: [AnyClass] {
        return [NSMeasurement.self]
    }
    
    public static func register() {
        let transformer = NSMeasurementValueTransformer()
        ValueTransformer.setValueTransformer(transformer, forName: name)
    }
}

有趣的是,我不必注册价值转换器。也许有人可以解释原因,但无需注册即可使用。

最后,在一个扩展中,我声明了一个面向公众的变量,它处理变量从我想要使用的测量值的转换,如下所示:

extension Item {
      public var length: Measurement<UnitLength> {
        // The getter returns an actual value, not an optional. If you want to return an optional, just use:
        // get { length_ as Measurement<UnitLength> }
        get { length_ as Measurement<UnitLength>? ?? Measurement(value: 0, unit: UnitLength.meters) }
        set { length_ = newValue as NSMeasurement }
    }

}

您会注意到核心数据属性被命名为length_。我仍然可以在我的应用程序中使用 Swift Measurements,但将它们安全地存储在 Core Data 中。这修复了核心数据警告:

CoreData:此应用程序中的一个或多个模型正在使用 具有未设置的转换器名称的可转换属性, 或设置为 NSKeyedUnarchiveFromDataTransformerName。请切换到 使用“NSSecureUnarchiveFromData”或 NSSecureUnarchiveFromDataTransformer 代替。在某些时候,核心数据 当 nil 为时,将默认使用“NSSecureUnarchiveFromData” 指定的和可转换的属性,其中包含不 支持 NSSecureCoding 将变得不可读。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-09
    • 2011-03-02
    • 2011-11-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多