ios - 删除 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!)
})
}
我的猜测是这是某种线程问题之类的。有没有人遇到过这个问题并知道如何解决这个问题?似乎它应该工作......
解决方案
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,请创建私有队列上下文并在私有上下文上执行导入。
推荐阅读
- ansible - Hashicorp Vault roleid 和 secretid 在创建为 ansible Vault Secret 时给出“unhexlify error: Odd-length string”
- python - Raspberry Pi 3 上的 aiy-python-wheels 出现问题。如何解决不兼容的 glibc 问题?
- azure - 有没有办法为现有 Azure 资源生成二头肌文件?
- python - 如何解决这个 Expected: ")" pylance 错误我得到一个 f 字符串?
- node.js - WebSocket接口不能代替WebSocket吗?
- haskell - 如何更新元组列表中的某个元组元素?
- python - 如何使 YOLO 输出到另一个程序的输入?
- c# - 复杂类型和等效类型之间的 AutoMapper Generic Cast
- android - Flutter:如何更新 CSV 单元格?
- amazon-web-services - 从 serverless.yml 创建时,Aurora Serverless 数据库集群未显示在 LocalStack 上