1

我有一个使用 Core Data 来持久存储Events的应用程序。

Event有一个可选的location(存储为 a CLLocation)作为其属性之一。在我的模型中,此location属性的类型为 Transformable:

Transformable 类型的 location 属性

我的应用程序已经投入生产好几年了,一切都在可靠地运行,但在过去的一年中,我开始在 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 并没有在应用程序启动时保留它,就像在更改之前一样。

有时Events 得救了,但有时却没有。

我想不出一个清晰的模式。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字段,以使事情像以前一样工作。

4

0 回答 0