Ios 核心数据中的安全编码测量类,NSValueTransformers
我有一个应用程序,大量使用测量。它是用SwiftUI/iOS 14编写的。我将数据保存在核心数据数据库中。在我尝试实现安全编码之前,该应用程序运行良好。我制作了一个示例应用程序,除去基本的东西。它基于Xcode的默认核心数据应用程序,几乎没有改动。同样,在我尝试使用安全编码之前,我可以很好地保存度量Ios 核心数据中的安全编码测量类,NSValueTransformers,ios,swift,core-data,swiftui,Ios,Swift,Core Data,Swiftui,我有一个应用程序,大量使用测量。它是用SwiftUI/iOS 14编写的。我将数据保存在核心数据数据库中。在我尝试实现安全编码之前,该应用程序运行良好。我制作了一个示例应用程序,除去基本的东西。它基于Xcode的默认核心数据应用程序,几乎没有改动。同样,在我尝试使用安全编码之前,我可以很好地保存度量 xddatamodel以及错误如下: 我正在为实体使用手动codegen,它如下所示: extension Item { @nonobjc public class func fetch
xddatamodel
以及错误如下:
我正在为实体使用手动codegen,它如下所示:
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 }
}
}
@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)
}
}
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 }
}
}
我的ValueTransformer如下所示:
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 }
}
}
@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)
}
}
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 }
}
}
据我所知,存在分歧,UnitLength的类标题为:
open class UnitLength : Dimension, NSSecureCoding
因此,它确实符合NSSecureCodeding
我使用了以下参考资料:
我仍然会遇到同样的错误:
Fatal error: Unresolved error Error Domain=NSCocoaErrorDomain Code=134060 "A Core Data error occurred.", [:]: file Core_Data_Test/ContentView.swift, line 57
我不知道我做错了什么导致了这次撞车。多亏了@LeoDabus,我终于能够解决这个问题。关键是将Swift测量转换为NSMEASURATION,并在核心数据中使用NSMEASURATION。您需要将自定义类设置为
NSMeasurement
。您的转换器将是自定义值转换器。我打电话给我的NSMeasurementValueTransformer
。您的.xcdatamodeld将如下所示:
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 }
}
}
@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)
}
}
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 }
}
}
我将自定义值转换器定义为:
@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 {
@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 }
}
}
@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)
}
}
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 }
}
}
扩展项{
公共变量长度:度量{
//getter返回的是实际值,而不是可选值。如果要返回可选值,只需使用:
//获取{length_uu作为度量值}
获取{length_uu作为度量值???度量值(值:0,单位:UnitLength.meters)}
将{length\=newValue设置为NSMeasurement}
}
}
您将注意到,核心数据属性的名称为length\uu
。我仍然可以在我的应用程序中使用Swift测量,但可以将它们安全地存储在核心数据中。这修复了核心数据警告:
CoreData:此应用程序中的一个或多个模型正在使用
具有未设置的转换器名称的可转换属性,
或者从DataTransformerName设置为NSKeyedUnachiveFromDataTransformerName。请转到
使用“NSSecureUnarchiveFromData”或
NSSecureUnarchiveFromDataTransformer。在某种程度上,核心数据
当为nil时,将默认使用“NSSecureUnarchiveFromData”
指定的,以及包含不包含
支持NSSecureCodeding将变得不可读
测量结果不符合要求NSSecureCoding@LeoDabus我检查过了,测量结果符合要求。有没有想过如何将其保存为NSMeasurement?NSMeasurement有,但Measurement没有