我在调试核心数据并发问题时遇到了问题。
在我的方案中我启用了:
-com.apple.CoreData.Logging.stderr 1
-com.apple.CoreData.ConcurrencyDebug 1
我想在后台线程中从核心数据中获取记录。
所以在我的 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__]
有没有人建议什么可能是问题?
最佳答案
当您尝试访问函数的结果时,就会发生多线程冲突。如果你使用 perform
,结果是空的——所以没有问题。如果您使用 performAndWait
,那么您返回的是几乎肯定在错误线程上访问的托管对象。
更糟糕的是,如果您尝试使用这些对象,您还会遇到错误访问错误。 ManagedObjects 不像普通的 NSObjects。 managedObject 只是一个 objectId 和一个指向上下文的指针。每当它需要访问其属性时,它会将请求转发到上下文。因此,如果该上下文被删除,那么这些对象将无法工作。在您的代码中,当函数结束时,支持结果的上下文将从内存中删除。 (注意:上下文并不总是立即删除。 在调试环境中,上下文可能会保留一段时间。在生产中,它会在函数结束时立即释放)。
因此访问该函数的结果是非法的,原因有两个 - 1) 您在错误的线程上,以及 2) 它没有后备上下文。
有几个解决方案。一种是从 managedObject 复制您需要的值并返回数组或字符串,或自定义对象(NSObject 子类)。
另一种解决方案是在应用程序生命周期内的主上下文中进行提取。
或者,您可以将要使用的上下文传递给函数。调用者有责任确保只要需要托管对象,上下文就会一直存在。
关于ios - 核心数据私有(private)上下文 performAndWait 导致调试崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45793211/