代码之家  ›  专栏  ›  技术社区  ›  Michael McKenna

为什么我在调用“privateManagedObjectContext”时会崩溃(从com.apple.main-thread(线程1)排队)。表演`?

  •  6
  • Michael McKenna  · 技术社区  · 6 年前

    在关闭网络请求时,我使用私有并发队列将对象插入核心数据,在私有上下文上调用“perform”时发生崩溃。

    控制台中的崩溃消息:

    libc++abi。dylib:以NSException类型的未捕获异常终止

    堆栈跟踪: enter image description here

    导致崩溃的代码:

    API.sync(onlyMe, syncToken: syncToken) { success, syncResponse in
        CoreDataUtils.privateContext.perform { // crashes on this line
            ....
        }
    }
    

    我的核心数据堆栈(不幸的是,目前位于AppDelegate中,而不是CoreDataStack类中):

    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
        // The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
        // Create the coordinator and store
        var coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        let url = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite")
        let options = [NSMigratePersistentStoresAutomaticallyOption: true,
                        NSInferMappingModelAutomaticallyOption: true]
        do {
            try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: options)
        } catch {
            print(error)
        }
    
        return coordinator
    }()
    
    lazy var privateManagedObjectContext: NSManagedObjectContext = {
        // Initialize Managed Object Context
        var managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    
        // Configure Managed Object Context
        managedObjectContext.parent = self.managedObjectContext
    
        return managedObjectContext
    }()
    
    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.
        var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        managedObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator
                managedObjectContext.mergePolicy = NSRollbackMergePolicy //This policy discards in-memory state changes for objects in conflict. The persistent store’s version of the objects’ state is used
    
        return managedObjectContext
    }()
    

    CoreDataUtils在哪里。privateContext是:

    class CoreDataUtils: NSObject {
    
        static let appDel = UIApplication.shared.delegate as! AppDelegate
        static let context: NSManagedObjectContext { 
            return appDel.managedObjectContext 
        }
        static let privateContext: NSManagedObjectContext {   
            appDel.privateManagedObjectContext 
        }
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Michael McKenna    6 年前

    我跟踪了@CodeBender的链接,发现有几个地方出现了多线程冲突。该链接提供了一种通过在项目方案中传递参数来调试并发性问题的方法。这种方法提供了关于哪里出了问题以及哪里出了问题的更好细节。

    例如,我有一个执行获取的函数,我没有将代码封装在 perform 块以下是我实施修复的方式:

    static func searchObject(in context: NSManagedObjectContext = context, _ entity: String, key: String, value: Any) -> [NSManagedObject]? {
    
        var objects: [NSManagedObject]?
    
        context.performAndWait {
            //searching core data for a specific attribute within an identity via a predicate
            let request = NSFetchRequest<NSFetchRequestResult>(entityName: "\(entity)")
            request.returnsObjectsAsFaults = false
            request.predicate = NSPredicate(format: "\(key) == %@", "\(value)")
    
            do {
                let results = try context.fetch(request)
                objects = results as? [NSManagedObject]
            } catch {
                let nserror = error as NSError
                Bugsnag.notifyError(nserror)
                NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
                abort()
            }
        }
    
    
        return objects
    }
    

    还有,在我插入的另一个地方 Notification 来自服务器的对象,我正在调用 表演 块,但我没有用适当的上下文实例化托管对象。

    CoreDataUtils.privateContext.perform {
        for notification in notifications {
    
            // BEFORE (WRONG) - would default to the main context (CoreDataUtils.context - see question)
            //notification.insert()
    
            // NOW (CORRECT) - inserts into private queue we are performing on
            notification.insert(into: CoreDataUtils.privateContext)
        }
    
        CoreDataUtils.save()
    }
    

    在哪里 通知 我有:

    func insert(into context: NSManagedObjectContext = CoreDataUtils.context) -> NotificationObject {
        assert(CoreDataUtils.searchObject(Models.notification, key: "id", value: self.id) == nil)
        let newNotification = NotificationObject(notification: self, context: managedObjectContext)
        return newNotification
    }