【问题标题】:App crashing when fetching NSObjects from background从后台获取 NSObjects 时应用程序崩溃
【发布时间】:2018-10-05 21:00:44
【问题描述】:

我收到NotificationCenter.default 的通知,该通知触发了一个 prune 方法,该方法在尝试从我的商店取货时崩溃。方法是这样的:

@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 的原因。

【问题讨论】:

    标签: swift core-data grand-central-dispatch nsnotificationcenter nsfetchrequest


    【解决方案1】:

    查看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
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      像这样手动检查线程来决定返回什么上下文不是一个好主意。

      调用者应该已经知道它需要什么上下文,所以只要请求它。复制 PersistentContainer 方法,并使用 viewContextnewBackgroundContext 方法返回准确的结果。

      当您最终放弃 iOS 9 时,您的迁移路径也会更轻松。

      -

      此外,无需手动分派到后台线程,私有上下文已经有自己的队列,它将执行 .perform {} 块。

      【讨论】:

        猜你喜欢
        • 2014-05-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多