首页 > 解决方案 > 删除 CoreData 对象会导致 EXC_BAD_INSTRUCTION

问题描述

我有一个基于列表的应用程序。为了支持将新元素添加到列表中,我所做的是在动作处理程序中创建一个新对象,并将其传递给详细信息视图。如果用户取消详细信息视图,我想删除该对象 - 当我这样做时,我得到一个EXC_BAD_INSTRUCTION.

一定有一些线程问题正在发生。

如果我在创建笔记后立即删除它(作为测试),它可以工作:

                Button(action: {
                    self.newNote = NoteDataManager.makeNote(moc: self.moc, folder: self.savingFolder)

                    // DELETE immediately, as a test
                    self.moc.delete(self.newNote!)
                    self.showNewNoteView = true
                }) {
                    Image(systemName: "square.and.pencil")
                }
                .sheet(isPresented: self.$showNewNoteView) {
                    CreateNoteView(newNote: self.newNote!, cancelAction: {
                        // DO NOTHING here (for now)
                    })
                }

但是,如果我在处理程序中删除它cancelAction(当用户点击取消按钮时调用它),我会得到异常:

                Button(action: {
                    self.newNote = NoteDataManager.makeNote(moc: self.moc, folder: self.savingFolder)

                    self.showNewNoteView = true
                }) {
                    Image(systemName: "square.and.pencil")
                }
                .sheet(isPresented: self.$showNewNoteView) {
                    CreateNoteView(newNote: self.newNote!, cancelAction: {
                        // MOVING the delete action here causes EXC_BAD_INSTRUCTION
                        self.moc.delete(self.newNote!)
                    })
                }

我的猜测是这是某种线程问题之类的。有没有人遇到过这个问题并知道如何解决这个问题?似乎它应该工作......

标签: ioscore-dataswiftui

解决方案


Core Data 被设计为在多线程环境中工作。然而,并不是 Core Data 框架下的每个对象都是线程安全的。要在多线程环境中使用 Core Data,请确保:

  • 托管对象上下文绑定到它们在初始化时关联的线程(队列)。
  • 从上下文中检索的托管对象绑定到上下文所绑定的同一个队列。

避免问题

一般来说,避免在与用户无关的主队列上进行数据处理。数据处理可能是 CPU 密集型的,如果在主队列上执行,可能会导致用户界面无响应。如果您的应用程序将处理数据,例如从 JSON 将数据导入 Core Data,请创建私有队列上下文并在私有上下文上执行导入。 不要在队列之间传递 NSManagedObject 实例。这样做可能会导致数据损坏和应用程序终止。当需要将托管对象引用从一个队列传递到另一个队列时,请使用 NSManagedObjectID 实例。您可以通过调用 NSManagedObject 实例上的 objectID 访问器来检索托管对象的托管对象 ID。

根据苹果文档

并发性是同时处理多个队列上的数据的能力。如果您选择使用 Core Data 的并发性,您还需要考虑应用程序环境。在大多数情况下,AppKit 和 UIKit 不是线程安全的。特别是在 macOS 中,Cocoa 绑定和控制器不是线程安全的——如果您使用这些技术,多线程可能会很复杂。

使用私有队列支持并发

一般来说,避免在与用户无关的主队列上进行数据处理。数据处理可能是 CPU 密集型的,如果在主队列上执行,可能会导致用户界面无响应。如果您的应用程序将处理数据,例如从 JSON 将数据导入 Core Data,请创建私有队列上下文并在私有上下文上执行导入。


推荐阅读