即使在 Core Data 上下文保存后数据也没有保留

Posted

技术标签:

【中文标题】即使在 Core Data 上下文保存后数据也没有保留【英文标题】:Data not persisted even after Core Data context save 【发布时间】:2017-07-21 09:03:52 【问题描述】:

我在核心数据的持久性方面遇到了一些问题。 我正在使用 NSSQLiteStoreType persistentStore(见下文)。 在我的应用程序中,每次我修改、创建或删除一些数据时,我都会通过调用 saveContext() 上面的函数立即将这些更改保存在我的核心数据中

但是,有时这些更改不会持续存在! (这个不持久的问题并不总是出现,我还是没有成功重现这个bug)

这是这些数据之一的生命周期:

用户修改 保存上下文(patient.managedObjectContext,其中患者是链接到所有其他数据实体的主要实体) 使用 AlamoFire 与后端同步 收到后端应答后在数据中设置远程ID 再次保存上下文(仍在 Alamofire 完成处理程序中:在主线程中执行,通过打印 Thread.current 进行检查)

最后,当这个错误发生时,它不仅影响一个数据,而且似乎影响从当前会话(从上次打开到关闭)修改和保存的所有数据

这是我的 coredatacontroller 的代码:

class CoreDataController: NSObject 

static let shared = CoreDataController()

var managedObjectContext: NSManagedObjectContext


override init() 
    // This resource is the same name as your xcdatamodeld contained in your project.
    guard let modelURL = Bundle.main.url(forResource: "xxx", withExtension:"momd") else 
        fatalError("Error loading model from bundle")
    
    // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.



    guard let mom = NSManagedObjectModel(contentsOf: modelURL) else 
        fatalError("Error initializing mom from: \(modelURL)")
    
    let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)

    let options = [ NSInferMappingModelAutomaticallyOption : true,
                    NSMigratePersistentStoresAutomaticallyOption : true]


    managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    managedObjectContext.persistentStoreCoordinator = psc

        let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        let docURL = urls[urls.endIndex-1]
        /* The directory the application uses to store the Core Data store file.
         This code uses a file named "DataModel.sqlite" in the application's documents directory.
         */
        let storeURL = docURL.appendingPathComponent("xxx.sqlite")
        do 
           try psc.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: options)
         catch let error  
            fatalError("Error migrating store: \(error)")
        

这里是我的 coredatacontroller 实例化的地方:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate 

var window: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
let coreDataController : CoreDataController = CoreDataController.shared

// FIXME: determiner le comportement attendu pour le badge sur l'icone et l'appliquer !!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 
    guard let window = window else 
        fatalError("Pas de window !!!")
     ......

这是我每次想在我的 coreData 中保存数据时使用的函数:

extension NSManagedObjectContext 

func saveContext() 
    do 
        try self.save()
     catch let error  
       print("Failure to save context: \(error)")
    

希望这个问题能启发你,并提前感谢你的想法!

编辑 1:

经过进一步调查,我所有的同步过程(包括 alamofire 请求)都在主线程中完成(我通过打印 Thread.current 检查了每一步)。

编号 = 1,名称 = 主要 dataFromJson 线程 编号 = 1,名称 = 主要 冲突处理者的线程 编号 = 1,名称 = 主要 fetchDataToSync 线程 编号 = 1,名称 = 主要

此外,在检查了我的后端数据库和我的 coredata 之间的差异之后,似乎 coredata 无法保存所有数据,直到应用程序崩溃(自愿或非自愿)然后重新启动应用程序,这将“重新启动”我的 coredata控制器。

【问题讨论】:

【参考方案1】:

很难确定,但有一个细节组合会带来麻烦,可能是导致此问题的原因。你提到

再次保存上下文(仍在 Alamofire 的线程中)

查看代码我看到了:

managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)

后来是这样的:

do 
    try self.save()
 catch let error  
   print("Failure to save context: \(error)")

因此,您有一个使用主队列并发的上下文,但是您只需调用save() 就可以保存主线程之外的更改。这不好。 Core Data 不是线程安全的,而且你正在跨线程。

要解决此问题,您确实需要在托管上下文中使用 performperformAndWait 方法,只要您在主线程之外使用它。这包括所有访问,可能以任何方式触及上下文的所有内容——获取请求、访问托管对象的属性或关系以及保存更改。这就是 Core Data 想要处理线程的方式。

【讨论】:

感谢您的建议!经过进一步调查,我所有的同步过程(包括 alamofire 请求)都在主线程中完成(我通过打印 Thread.current 检查了每一步)。此外,在检查了我的后端数据库和我的 coredata 之间的差异之后,似乎 coredata 无法保存所有数据,直到应用程序崩溃(自愿或非自愿)然后重新启动将“重新启动”我的 coredata 控制器的应用程序。 今天我解决了这个问题,你对它的来源是对的。一个回调试图访问 coredata nd 是造成这些错误的原因! 你好,保罗,我能告诉我更多你发现了什么吗?我正在努力解决同样的问题。所以没有崩溃,只是有时核心数据中的数据丢失,我无法重现它。应用程序崩溃了吗?还是只是无法保存数据(所以您丢失了一些数据?)

以上是关于即使在 Core Data 上下文保存后数据也没有保留的主要内容,如果未能解决你的问题,请参考以下文章

将 Core Data XML 存储同步到磁盘

iPhone Core Data 一次保存多个项目的随机行为?

多上下文麻烦。无法在 Core Data 中创建两个队列(主队列和私有队列)保存数据

ios/xcode/core data:更新屏幕的最佳方式

Core Data 后台处理,保存不推送到主上下文

即使在删除之后,Core Data 命令也会使 ViewController 崩溃