I make a list for audio items from coredata. after deleting, crash reported as "EXC_BREAKPOINT (code=1, subcode=0x1b8fb693c)", why?
When using
ForEach(items, id: \.self)
, it works. But My Audio has id property and follow Identifiable protocol.
UPDATE: I found adding a if{} clause will fix crash, but why? Breakpoint at "static 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()
})
}
}
}
code as following:
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()
})
}
}
}
I had the same problem as you.
Probably it is a bad idea to use your own id
property to make it Identifiable
because Core Data is setting all the properties to nil
when the object is deleted, even if you declared it differently in your Swift CoreData class.
When deleting your entity, the id
property gets invalidated and the objects .isFault
property is set to true
, but the SwiftUI ForEach
still holds some reference to this ID object (=your UUID) to be able to calculate the "before" and "after" state of the list and somehow tries to access it, leading to the crash.
Therefore the following recommendations:
ForEach
loop by checking isFault
:if entity.isFault {
EmptyView()
}
else {
// your regular view body
}
id
property to be nil
, either by defining it accordingly in your core data model as optional@NSManaged public var id: UUID?
or by not relying on the Identifiable
protocol in the SwiftUI ForEach
loop:
ForEach(entities, id: \.self) { entity in ... }
or
ForEach(entities, id: \.objectID) { entity in ... }
Conclusion: you really do not need to make all your CoreData properties Swift Optional
s. It's simply important that your id
property referenced in the ForEach
loop handles the deletion (=setting its value to nil
) gracefully.
I found the reason of crash, must provide optional, because of OC/swift object conversion:
convert
class Audio: NSManagedObject, Identifiable {
@NSManaged public var id: UUID
@NSManaged public var name: String
@NSManaged public var createAt: Date
}
to
class Audio: NSManagedObject, Identifiable {
@NSManaged public var id: UUID?
@NSManaged public var name: String?
@NSManaged public var createAt: Date?
}
I had the same issue over the weekend. It looks like SwiftUI want's to unwrap the value i read from CoreData and as the value is already deleted it crashes.
In my case i did solve it with nil coalescing on all values i use from CoreData.
You can try to provide a default value on your item.name with
ForEach(items) { item in
HStack {
Text("\(item.name ?? "")")
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With