我有一个使用 Core Data 来持久存储Events的应用程序。
Event有一个可选的location
(存储为 a CLLocation
)作为其属性之一。在我的模型中,此location
属性的类型为 Transformable:
我的应用程序已经投入生产好几年了,一切都在可靠地运行,但在过去的一年中,我开始在 Xcode 控制台中收到一个错误,告诉我应该改用“NSSecureUnarchiveFromData”或 NSSecureUnarchiveFromDataTransformer 的子类。
在做了一些研究之后(我认为自己是 Core Data 的新手),我决定我应该编写一个NSSecureUnarchiveFromDataTransformer
子类并将该类的名称放在属性的Transformer字段中,该location
属性是空白的,带有Value Transformer Name占位符文本:
根据我在网上找到的内容,对于包含以下内容的 Transformable 属性,子类可能非常简单CLLocation
:
@objc(CLLocationValueTransformer)
final class CLLocationValueTransformer: NSSecureUnarchiveFromDataTransformer {
static let name = NSValueTransformerName(rawValue: String(describing: CLLocationValueTransformer.self))
override static var allowedTopLevelClasses: [AnyClass] {
return [CLLocation.self]
}
public static func register() {
let transformer = CLLocationValueTransformer()
ValueTransformer.setValueTransformer(transformer, forName: name)
}
}
所以,我在我的项目中创建了这个子类,并将类名放在属性的Transformer字段中location
:
但是现在,问题出现了: 在实现 Transformer 后开始使用我的应用程序后,我开始得到不可预测的结果。
有时,当我创建一个新的 时Event
,它会在下一次应用启动时消失。Core Data 并没有在应用程序启动时保留它,就像在更改之前一样。
有时Event
s 得救了,但有时却没有。
我想不出一个清晰的模式。location
如果在首次创建时包含 ,则它们并不总是被保存 ,但有时它们会被保存。似乎其他时候原件Event
被保存了,但location
如果location
是后来添加的,则没有。
我省略了样板核心数据代码,但基本上我有baseManagedObjectContext
,这是连接到NSPersistentStoreCoordinator
将数据保存到磁盘的层。
baseManagedObjectContext
是 的父mainObjectContext
级,我的大部分 UI 都使用它。然后我创建私有上下文以在保存更改之前先写入更改。
Event
这是使用可能创建一个新location
对象并保存它的示例代码,在将NSSecureUnarchiveFromDataTransformer
子类添加为location
. 我添加fatalError
了调试,但它从未被调用,即使我的数据没有完全保存到磁盘:
private func addEvent(location: CLLocation?) {
let privateLocalContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
privateLocalContext.parent = coreDataStack.mainObjectContext
privateLocalContext.undoManager = nil
let entity = NSEntityDescription.entity(forEntityName: "Event",
in: privateLocalContext)
let newEvent = Event(entity: entity!,
insertInto: privateLocalContext)
if let location = location {
newEvent.location = location
}
privateLocalContext.performAndWait {
do {
try privateLocalContext.save()
}
catch { fatalError("error saving privateLocalContext") }
}
coreDataStack.mainObjectContext.performAndWait {
do {
try coreDataStack.mainObjectContext.save()
}
catch { fatalError("error saving mainObjectContext") }
}
coreDataStack.baseManagedObjectContext.perform {
do {
try coreDataStack.baseManagedObjectContext.save()
}
catch { fatalError("error saving baseManagedObjectContext") }
}
}
通过进一步调试,我发现有时,即使更改为mainObjectContext
,它也没有一直到baseManagedObjectContext
或磁盘。我创建了一个完整的独立核心数据堆栈,用于测试直接从磁盘读取。
这个保存不传播的问题(就像他们以前多年来所做的那样)是导致数据在应用程序启动时无法持续存在的原因,但我不明白为什么在我添加Transformer后突然开始发生这种情况location
。
Core Data 是如何工作的,我在这里缺少什么?
当我从一个空白的Transformer字段切换到NSSecureUnarchiveFromDataTransformer
.
我想采用NSSecureUnarchiveFromDataTransformer
,因为 Apple 推荐它。我怎样才能改变我正在做的事情才能采用它并一致地保存数据?
现在,我已经切换回空白的Transformer字段,以使事情像以前一样工作。