我们正在通过Citrix Secure Hub运行应用程序,似乎有时会回滚,因为CoreData中的某些数据丢失了。
据我了解,CoreData具有所有对象的工作副本之类的功能,有时会尝试将其持久化在文件系统上。
Well试图模拟这种行为,但是没有成功,我们无法在测试环境中发现任何数据丢失或回滚的数据。
那么有没有一种方法可以迫使iOS在磁盘上写入当前的“工作副本”,以防止在使用过多内存(可能崩溃)时丢失任何数据?
之后,我们调用保存功能我们已经发现:
我们没有使用:
func applicationWillResignActive(_ application: UIApplication) {
print("applicationWillResignActive")
}
要保存上下文,这可能是个问题(我们已经在创建每个对象之后保存了上下文)吗?
目前,当无法保存上下文时,我们并没有真正处理问题,是否有任何建议在生产环境中如何处理?也许崩溃使应用程序阻止用户陷入数据丢失困境是件好事吗?
编辑:这是使用的核心数据处理程序:
import Foundation
import CoreData
let context = CoreDataManager.shared.managedObjectContext
func saveContext(_ completion: (() -> Void)? = nil) {
CoreDataManager.shared.save(completion)
}
func saveContextSync() {
CoreDataManager.shared.saveSync()
}
class CoreDataManager: NSObject {
static let shared = CoreDataManager()
lazy var managedObjectContext: NSManagedObjectContext = {
var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator
return managedObjectContext
}()
还有我们的保存功能:
@objc func save(_ completion: (() -> Void)?) {
saveAsync(completion)
}
func saveAsync(_ completion: (() -> Void)?) {
func save() {
context.perform {
do { try context.save() }
catch {
// HERE WE NEED TO HANDLE IT FOR A PRODUCTIVE ENVIRONMENT
}
completion?()
}
}
if Thread.isMainThread {
save()
} else {
DispatchQueue.main.async {
save()
}
}
}
func saveSync() {
func save() {
context.performAndWait {
do { try context.save() }
catch { print(error)
// TRY TO REPRODUCE MEMORY LOSS APP TO SEE WHAT HAPPENS
abort()
}
}
}
if Thread.isMainThread {
save()
} else {
DispatchQueue.main.sync {
save()
}
}
}
编辑2:目标C中的这个问题应该非常相似:
Core Data reverts to previous state without apparent reason
编辑3:似乎没有崩溃,一些用户告诉我他们正在添加数据,然后只需按主页按钮,几个小时后,最后一个“任务”中的数据就会丢失。
答案 0 :(得分:1)
有三种可能的原因。
核心数据通常希望以单个同步方式完成写入。如果您以多种方式同时写入同一对象(即使它们接触不同的属性并且没有严格冲突),则将是合并冲突。您可以设置合并策略(默认情况下,值为“错误”-表示不应用更改),但这确实是一个糟糕的解决方案,因为您会告诉核心数据静默丢失信息。有关防止合并冲突的设置,请参见NSPersistentContainer concurrency for saving to core data。
如果正确设置核心数据,则不会发生这种情况。将核心数据设置为仅从“ viewContext”读取并以单个同步方式写入的正确方法。每次编写都在单个atomic块中完成,并且仅在保存后更新UI。如果您显示的是未保存到磁盘的上下文信息,则可能会出现问题。例如,看来您的应用程序仅使用单个主线程上下文进行读取和写入。对该上下文进行更改而不调用save将使应用程序处于仅在内存中而不在磁盘上的主要更改状态。
这是迄今为止最罕见的事件,但是有些用户的磁盘实际上已经满了。如果发生这种情况,您将无法进行任何保存。磁盘上实际上没有剩余空间。通常,正确的做法是告诉用户,然后留给用户。
在不了解您的特定设置的情况下,很难确定您的问题是什么。我建议您进行以下设置:
NSPersistentContainer
viewContext
读取,从不写入。这应该处理除第三个问题以外的所有问题。