由于未捕获的异常终止应用程序' NSInternalInconsistencyException',原因:' Context已经有一个协调员;无法取代

时间:2014-12-22 02:14:45

标签: ios multithreading core-data nsmanagedobjectcontext

我无法处理Core Data并使用Parent/Child context method处理multithreading with Core Data

这是我的应用程序在核心数据和多线程方面的流程:

  1. 使用Alamofire从服务器接收JSON
  2. 在Alamofire响应中创建后台线程并解析JSON
  3. 解析信息转换为NSManagedObject类(仍在bg线程中)
  4. NSManagedObject类被传递给我的DatabaseManager类(仍在bg线程中)
  5. DatabaseManager init创建Child Context(仍然在bg线程中),并设置Parent Context
  6. 使用NSBatchUpdate更新Core Data中的对象
  7. DatabaseManager performBlock并保存Child和Parent上下文
  8. 我收到了错误:

    由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'上下文已经有一个协调器;无法取代。

    有时我会同时多次调用服务器。这可能是一个相关的问题,因为performBlock会阻止父上下文在尝试保存时(例如从另一个线程)?

    从我到目前为止所读到的关于使用核心数据和多线程的Parent/Child上下文方法,我已经理解,基本上当你尝试从后台线程保存时,它将阻止当前的子和父上下文并保存更改。但是如果具有不同子上下文的另一个后台线程试图同时保存会发生什么?

    同样是旁注,在我的DatabaseManager类中,我一直在使用父上下文来获取更新请求,使用子上下文来获取更新请求。这会造成问题吗?

    这是我用来获取Parent Context的单个实例的方法:

    // In my DatabaseManager class
    lazy var parentContext: NSManagedObjectContext? = {
        let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        if let managedObjectContext = appDelegate.managedObjectContext {
            return managedObjectContext
        }
        else {
            return nil
        }
        }()
    
    // In my AppDelegate
    lazy var managedObjectContext: NSManagedObjectContext? = {
        // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
        let coordinator = self.persistentStoreCoordinator
        if coordinator == nil {
            return nil
        }
        var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
        managedObjectContext.persistentStoreCoordinator = coordinator
        managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        return managedObjectContext
    }()
    

    DatabaseManager类init和saveContext方法:

    init(child: NSManagedObjectContext) {
        childContext = child
        childContext!.parentContext = parentContext
    }
    
    func saveContext() {
        if parentContext != nil && childContext != nil {
            childContext!.performBlock({
                var childError: NSError? = nil
                if self.childContext!.save(&childError) {
                    println("Child context saved")
    
                    self.parentContext!.performBlock({
                        var parentError: NSError? = nil
                        if self.parentContext!.save(&parentError) {
                            println("Parent context saved")
                        }
                        else {
                            println("Parent context saving error: \(parentError?.localizedDescription)")
                        }
                    })
                }
                else {
                    println("Child context saving error: \(childError?.localizedDescription)")
                }
            })
        }
    }
    

    在我的HttpResponseManager中创建子上下文,处理来自服务器调用的响应

    class HttpResponseManager {
    
    let db: DatabaseManager?
    lazy var parentContext: NSManagedObjectContext? = {
        let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        if let managedObjectContext = appDelegate.managedObjectContext {
            return managedObjectContext
        }
        else {
            return nil
        }
        }()
    let childContext: NSManagedObjectContext?
    
    init() {
        childContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
        childContext!.parentContext = parentContext
        db = DatabaseManager(child: childContext!)
    }
    
    func handleGameInfo(json: JSON) {
        let arr = JSON(json[GlobalVars.kEventGameInfoGet].arrayObject!)
    
        for (index: String, obj: JSON) in arr {
            var game = NSEntityDescription.insertNewObjectForEntityForName("Game", inManagedObjectContext: self.childContext!) as Game
    
            game.id = obj[GlobalVars.kId].stringValue
            game.name = obj[GlobalVars.kName].stringValue
            game.platform = obj[GlobalVars.kPlatform].stringValue
            game.genre = obj[GlobalVars.kGenre].stringValue
            game.coverPhoto = (obj[GlobalVars.kCoverPhoto].arrayValue)[0].stringValue
    
            if db != nil {
                db!.updateGame(game)
            }
        }
    }
    
    }
    

0 个答案:

没有答案