删除 CoreData 对象会导致 EXC_BAD_INSTRUCTION

Posted

技术标签:

【中文标题】删除 CoreData 对象会导致 EXC_BAD_INSTRUCTION【英文标题】:Deleting CoreData object results in EXC_BAD_INSTRUCTION 【发布时间】:2020-06-21 19:32:32 【问题描述】:

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

我的猜测是这是某种线程问题之类的。有没有人遇到过这个问题并知道如何解决这个问题?看来应该可以了……

【问题讨论】:

尝试将该行分成两行。第一个是let n = self.newNote!,第二个是self.moc.delete(n)。我想知道是! 导致它崩溃(即newNote 为零)。 不是——我试过了,谢谢你的建议!我还浏览了调试器,动作处理程序成功了。崩溃发生在 SwiftUI 框架代码中。 【参考方案1】:

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

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

避免问题

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

根据苹果documentation

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

使用私有队列支持并发

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

【讨论】:

以上是关于删除 CoreData 对象会导致 EXC_BAD_INSTRUCTION的主要内容,如果未能解决你的问题,请参考以下文章

如何删除此 EXC_BAD 访问错误?

我无法重现的用户可能会导致 CoreData 崩溃

CoreData + CloudKit 支持的 App 在导出(export)新建托管对象时内存飙升导致被杀死的解决

CoreData不删除对象一对多实体

Core Data 对象删除使应用程序崩溃

当我删除相关对象时,为啥 Core Data 会复活已删除的对象?