在 SwiftUI 中从 coredata 中删除记录时崩溃

foo*_*ear 5 core-data swiftui

我从 coredata 中列出了音频项目。删除后,崩溃报告为“EXC_BREAKPOINT (code=1, subcode=0x1b8fb693c)”,为什么?

使用时

ForEach(items, id: \.self)
Run Code Online (Sandbox Code Playgroud)

, 有用。但我的音频具有 id 属性并遵循可识别协议。

更新:我发现添加 if{} 子句可以修复崩溃,但为什么呢?断点在“静态 UUID。unconditionallyBridgeFromObjectiveC ( :) ()”。

struct Test1View: View {
    @Environment(\.managedObjectContext) var context
    @FetchRequest(fetchRequest: Audio.fetchAllAudios()) var items: FetchedResults<Audio>
    var body: some View {
        List {
            ForEach(items) { item in
                if true { // <- this if clause fix crash, but why?
                    HStack {
                        Text("\(item.name)")
                    }
                }
            }.onDelete(perform: { indexSet in
                let index = indexSet.first!
                let item = self.items[index]
                self.context.delete(item)
                try? self.context.save()
            })
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

代码如下:

class Audio: NSManagedObject, Identifiable {
    @NSManaged public var id: UUID
    @NSManaged public var name: String
    @NSManaged public var createAt: Date
}

struct Test1View: View {
    @Environment(\.managedObjectContext) var context
    var fetchRequest: FetchRequest<Audio> = FetchRequest<Audio>(entity: Audio.entity(), sortDescriptors: [NSSortDescriptor(key: "createAt", ascending: false)])
    var items: FetchedResults<Audio> { fetchRequest.wrappedValue }
    var body: some View {
        List {
            ForEach(items) { item in
                HStack {
                    Text("\(item.name)")
                }
            }.onDelete(perform: { indexSet in
                let index = indexSet.first!
                let item = self.items[index]
                self.context.delete(item)
                try? self.context.save()
            })
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

pd9*_*d95 6

我和你有同样的问题。

使用您自己的id属性来创建它可能是一个坏主意,Identifiable因为 Core Data 将所有属性设置nil为删除对象时,即使您在 Swift CoreData 类中声明它不同。删除您的实体时,该id属性将失效并且 objects.isFault属性设置为true,但 SwiftUIForEach仍保留对此 ID 对象(=您的 UUID)的一些引用,以便能够计算列表的“之前”和“之后”状态并以某种方式尝试访问它,导致崩溃。

因此有以下建议:

  1. 保护详细视图(在ForEach循环中通过检查isFault
if entity.isFault {
    EmptyView()
}
else {
    // your regular view body
}
Run Code Online (Sandbox Code Playgroud)
  1. 期望您的id属性为nil,或者通过在您的核心数据模型中将其相应地定义为可选
@NSManaged public var id: UUID?
Run Code Online (Sandbox Code Playgroud)

或者不依赖IdentifiableSwiftUIForEach循环中的协议:

ForEach(entities, id: \.self) { entity in ... }
Run Code Online (Sandbox Code Playgroud)

或者

ForEach(entities, id: \.objectID) { entity in ... }
Run Code Online (Sandbox Code Playgroud)

结论:您真的不需要将所有 CoreData 属性都设置为 Swift Optional。循环中id引用的属性优雅地ForEach处理删除(=将其值设置为nil)非常重要。