从后台获取 NSObjects 时应用程序崩溃
App crashing when fetching NSObjects from background
我有一个 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
}
我还没有找到重现此崩溃的方法,我只是在 Apple 崩溃报告中找到它。这是回溯:
Book 绝对是实体,被命名为 Book,所以我知道这不是问题所在。另外,我很困惑为什么它不会捕获而不是崩溃。
注意:该应用程序适用于 iOS 9 岁及以上,这就是我不使用 NSPersistentContainer
.
的原因
查看 this page Apple 文档。您面临的问题是您自己创建后台队列,而 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
}
}
}
像这样手动检查线程来决定将什么上下文 return 不是一个好主意。
调用者应该已经知道它需要什么上下文,所以直接询问即可。复制 PersistentContainer 方法并具有 viewContext
和 newBackgroundContext
方法,return 完全相同。
当你最终放弃 iOS 9.
时,你的迁移路径也会更容易
-
也不需要手动分派到后台线程,私有上下文已经有自己的队列,它将在其上执行 .perform {}
块。
我有一个 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
}
我还没有找到重现此崩溃的方法,我只是在 Apple 崩溃报告中找到它。这是回溯:
Book 绝对是实体,被命名为 Book,所以我知道这不是问题所在。另外,我很困惑为什么它不会捕获而不是崩溃。
注意:该应用程序适用于 iOS 9 岁及以上,这就是我不使用 NSPersistentContainer
.
查看 this page Apple 文档。您面临的问题是您自己创建后台队列,而 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
}
}
}
像这样手动检查线程来决定将什么上下文 return 不是一个好主意。
调用者应该已经知道它需要什么上下文,所以直接询问即可。复制 PersistentContainer 方法并具有 viewContext
和 newBackgroundContext
方法,return 完全相同。
当你最终放弃 iOS 9.
时,你的迁移路径也会更容易-
也不需要手动分派到后台线程,私有上下文已经有自己的队列,它将在其上执行 .perform {}
块。