即使在核心数据上下文保存

时间:2017-07-21 09:03:52

标签: ios swift core-data

我面临着核心数据持续存在的一些问题。 我使用的是NSSQLiteStoreType persistentStore(见下文)。 在我的应用程序中,每次我修改,创建或删除某些数据时,我都会通过调用saveContext()

上面的函数立即将这些更改保存在我的coredata中

但是,这些变化不会持续存在! (这种非持久性的问题并不总是存在,我仍然没有成功地故意重现这个错误)

以下是其中一个数据的lifeCycle:

  • 用户修改
  • 保存上下文(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检查了每一步)。

 {number = 1, name = main}
thread of dataFromJson
{number = 1, name = main}
thread of conficthandler
{number = 1, name = main}
thread of fetchDataToSync
{number = 1, name = main}

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

1 个答案:

答案 0 :(得分:0)

很难确定,但是有一个细节组合会造成麻烦,而可能会导致此问题。你提到

  

再次保存上下文(仍在Alamofire的主题中)

查看代码,我看到了:

managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)

后来有了这个:

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

因此,您有一个使用主队列并发的上下文,但您只需调用save()即可保存主线程的更改。这不好。核心数据不是线程安全的,而且你正在跨越线程。

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