我收到一个带有NotificationCenter.default
的通知,该通知触发一个修剪方法,该修剪方法在尝试从商店中获取时崩溃。这是方法:
@objc fileprivate func pruneBooks() {
DispatchQueue.global(qos: .background).async {
let context = cdStack.getManagedObjectContext()
context.perform {
do{
let request = NSFetchRequest<Book>(entityName: "Book")
let result = try context.fetch(request)\\ <----- CRASHES HERE
//DO STUFF
}catch{
// Handle Error
}
}
}
}
这是我的getManagedObjectContext
方法的样子:
func getManagedObjectContext() -> NSManagedObjectContext {
let thread = Thread.current
if thread.isMainThread {
return mainMOC
}
let childContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
childContext.parent = mainMOC
NotificationCenter.default.addObserver(self,
selector: #selector(didReceiveChildContextDidSave(notification:)),
name: .NSManagedObjectContextDidSave,
object: childContext)
return childContext
}
我还没有找到重复此崩溃的方法,我只是在苹果崩溃报告中得到了它。这是回溯:
Book绝对是实体,被命名为Book,所以我知道这不是问题。另外,我对为什么它不被抓住而不是崩溃感到困惑。
注意:该应用程序适用于iOS 9及更高版本,这就是为什么我不使用NSPersistentContainer
的原因。
答案 0 :(得分:1)
查看Apple文档中的this page。您面临的问题是由于您自己创建了后台队列,而ManagedObjectContext
却有它自己。可以通过perform
方法访问此队列,该方法在该队列上执行您的块(因此在后台执行)。如果我是对的,则应删除pruneBooks
函数的第一行,使其看起来像这样:
@objc fileprivate func pruneBooks() {
let context = cdStack.getManagedObjectContext()
context.perform {
do{
let request = NSFetchRequest<Book>(entityName: "Book")
let result = try context.fetch(request)\\ <----- CRASHES HERE
//DO STUFF
}catch{
// Handle Error
}
}
}
答案 1 :(得分:1)
像这样手动检查线程以确定要返回的上下文不是一个好主意。
呼叫者应该已经知道它需要什么上下文,因此只需提出要求。复制PersistentContainer方法并使用viewContext
和newBackgroundContext
方法来返回该值。
当您最终放弃iOS 9时,您的迁移路径也会更容易。
-
此外,也无需手动调度到后台线程,私有上下文已经具有自己的队列,可以在其上执行.perform {}
块。