【发布时间】:2020-12-22 21:55:07
【问题描述】:
我开发了一个 ios 应用程序,允许用户编辑乐谱表,现在我想实现数据持久性以防止丢弃更改。
阅读 ios 文档后,我注意到存在改善数据持久性的不同方法,我相信对我的应用程序来说最好的方法是 Core Data。 考虑到我的应用程序使用了很多自定义对象,我遇到了很多问题。
我正在尝试使用核心数据来保存一个实体,称为分数表,由两个属性组成:
- 名称:字符串
- score:另一个自定义对象(Measure)的数组,由其他自定义对象(Score Element)组成
根据文档和其他 q/a,我决定在模型上使用 Trasformable 类型:
所以我声明了一个通用类,用作 score 属性的转换器:
public class NSSecureCodingValueTransformer<T: NSSecureCoding & NSObject>: ValueTransformer {
public override class func transformedValueClass() -> AnyClass { T.self }
public override class func allowsReverseTransformation() -> Bool { true }
public override func transformedValue(_ value: Any?) -> Any? {
guard let value = value as? T else { return nil }
return try? NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true)
}
public override func reverseTransformedValue(_ value: Any?) -> Any? {
guard let data = value as? NSData else { return nil }
let result = try? NSKeyedUnarchiver.unarchivedObject(
ofClass: T.self,
from: data as Data
)
return result
}
/// The name of this transformer. This is the name used to register the transformer using `ValueTransformer.setValueTransformer(_:forName:)`
public static var transformerName: NSValueTransformerName {
let className = NSStringFromClass(T.self)
return NSValueTransformerName("DHC\(className)ValueTransformer")
}
/// Registers the transformer by calling `ValueTransformer.setValueTransformer(_:forName:)`.
public static func registerTransformer() {
let transformer = NSSecureCodingValueTransformer<T>()
ValueTransformer.setValueTransformer(transformer, forName: transformerName)
}
}
以这种方式使用 DHCMeasureValueTransformer 作为 DataModel 文件中的转换器。 问题是,当我保存时,没有发生错误,但是当我为重新启动应用程序获取数据时,我可以只获取分数表的名称,而分数数组是空的,就像没有元素放在里面一样(显然,在保存之前,我尝试打印数组内容,这证明我正在使用非空数组)
这是保存的代码:
static func saveContext() {
let context = getContext()
do {
try context.save()
} catch {
print("error during the save.")
}
}
这里是实体对象的两个类的代码:
// DataClass
@objc(ScoreSheet)
public class ScoreSheet: NSManagedObject {
static var supportsSecureCoding: Bool {
return true
}
}
//DataProperties
extension ScoreSheet {
@nonobjc public class func fetchRequest() -> NSFetchRequest<ScoreSheet> {
return NSFetchRequest<ScoreSheet>(entityName: "ScoreSheet")
}
@NSManaged public var name: String
@NSManaged public var score: [Measure]
}
Clearly Measure 类实现了 NSSecureCoding 和对对象进行解码和编码的方法。
这里是 Measure 类的实现:
import Foundation
class Measure: NSObject, NSCoding, NSSecureCoding {
var elements : [ScoreElement] = []
var timeSig : TimeSignature
var clef : Clef
static var supportsSecureCoding = true
init(time : TimeSignature, clef : Clef) {
self.timeSig = time
self.clef = clef
}
func encode(with encoder: NSCoder) {
encoder.encode(self.elements, forKey: "elements")
encoder.encode(self.timeSig, forKey: "timeSig")
encoder.encode(self.clef, forKey: "clef")
}
required convenience init? (coder decoder: NSCoder) {
let elements = decoder.decodeObject(forKey: "elements") as! [ScoreElement]
let timeSig = decoder.decodeObject(forKey: "timeSig") as! TimeSignature
let clef = decoder.decodeObject(forKey: "clef") as! Clef
self.init(time: timeSig, clef: clef)
self.elements = elements
}
}
【问题讨论】:
-
答案将取决于
Measure类的实现方式。到目前为止,您包含的代码并未显示Measure实现了该协议。 -
我已经编辑了问题并添加了 Measure 类
标签: ios swift core-data swift5