调试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__]
有没有人有什么建议可以成为问题?
答案 0 :(得分:2)
当您尝试访问函数的结果时,会发生多线程冲突。如果您使用perform
,结果为空 - 所以没有问题。如果您使用performAndWait
,那么您将返回几乎肯定在错误的线程上访问的managedObjects。
更糟糕的是,如果您尝试使用这些对象,也会遇到错误访问错误。 ManagedObjects不像普通的NSObjects。 managedObject只是一个objectId和一个指向上下文的指针。只要需要访问其属性,它就会将请求转发给上下文。因此,如果删除该上下文,那么这些对象将无法工作。在您的代码中,当函数结束时,将从内存中删除支持结果的上下文。 (注意:并不总是立即删除上下文。 在调试环境中,上下文可以保持一段时间。在生产中,它会在功能结束时立即发布。)
因此,访问函数的结果是非法的,原因有两个--1)你的错误线程和2)它没有支持上下文。
有一些解决方案。一种方法是从managedObject复制所需的值并返回一个或多个数组或自定义对象(NSObject子类)。
另一个解决方案是在主应用上下文中进行提取,该主要用户应用程序的生命周期。
或者,您可以传递要用于该函数的上下文。并且只要需要managedObjects,调用者就有责任确保上下文保持不变。