核心数据私有上下文performAndWait导致调试崩溃

时间:2017-08-21 09:06:21

标签: ios swift core-data

调试Core Data并发问题时遇到问题。

在我的计划中,我启用了:

-com.apple.CoreData.Logging.stderr 1
-com.apple.CoreData.ConcurrencyDebug 1

我想在后台线程中从Core Data中获取记录。

所以在我的UIViewController我创建了DispatchQueue.global(qos: .background).async,我在其中调用Core Data来获取记录。

我正在使用父母/孩子:

    func performStationsFetch(filter: String = "") -> [Stations] {
    let privateMOC = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    let parentMOC = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext

    privateMOC.parent = parentMOC

    var fetchResults: [Stations] = []

    privateMOC.performAndWait {
        let fetchRequest: NSFetchRequest<Stations> = Stations.fetchRequest()
        fetchRequest.predicate = NSPredicate(format: "name contains[c] %@", filter)

        do {
            fetchResults = try privateMOC.fetch(fetchRequest)
        } catch {
            print("Fetch error")
        }
    }

    return fetchResults
}

问题是如果我调用privateMOC.perform代码工作正常。

但如果我致电privateMOC.performAndWait,代码会崩溃并给我+[NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__]

有没有人有什么建议可以成为问题?

1 个答案:

答案 0 :(得分:2)

当您尝试访问函数的结果时,会发生多线程冲突。如果您使用perform,结果为空 - 所以没有问题。如果您使用performAndWait,那么您将返回几乎肯定在错误的线程上访问的managedObjects。

更糟糕的是,如果您尝试使用这些对象,也会遇到错误访问错误。 ManagedObjects不像普通的NSObjects。 managedObject只是一个objectId和一个指向上下文的指针。只要需要访问其属性,它就会将请求转发给上下文。因此,如果删除该上下文,那么这些对象将无法工作。在您的代码中,当函数结束时,将从内存中删除支持结果的上下文。 (注意:并不总是立即删除上下文。 在调试环境中,上下文可以保持一段时间。在生产中,它会在功能结束时立即发布。)

因此,访问函数的结果是非法的,原因有两个--1)你的错误线程和2)它没有支持上下文。

有一些解决方案。一种方法是从managedObject复制所需的值并返回一个或多个数组或自定义对象(NSObject子类)。

另一个解决方案是在主应用上下文中进行提取,该主要用户应用程序的生命周期。

或者,您可以传递要用于该函数的上下文。并且只要需要managedObjects,调用者就有责任确保上下文保持不变。