SwiftUI Core Data crash when deleting an object

When using @ObservedObject with a Core Data object, my SwiftUI view crashes when the object is deleted. SwiftUI evaluates the body after the object is deleted causing the view to access properties of a deleted object, leading to the crash.

The object in question is deleted on a background context as a result of a network call, if that helps (not sure why that would matter).

i can avoid the crash by having a giant if condition around the entire body of my view that checks the isDeleted flag of the Core Data object, but doing so seems rather silly.

i am really hoping there is a more elegant solution to this issue.

Has anyone run into this and is there a better way to avoid the crash?

Replies

If an object can be deleted while it's being displayed, you definitely should check isDeleted and handle it gracefully.

If it's deleted, why not display different information in the view, like, "Sorry, couldn't load this thing"?

hi,

in many cases when you delete the Core Data object, SwiftUI may try to execute the body property of a view in which you reference the object as @ObservedObject.

i recall checking the .isDeleted property and it did not always seem to return the right value ... but something that is true about the deleted object will be that all its attributes will be zeroed out. so, all optional properties will be nil, all numeric values will be 0, a date will be back in 1970 somewhere, all relationships will be nil, and so forth.

if you have nil-coalesced all properties of the Core Data object, then everything should pretty much just work. for example:

Text(myObject.name ?? "No Name")

will not crash your app, but

Text(myObject.name!)

will certainly crash.

i usually add an extension to a Core Data object so that every property is nil-coalesced. e.g., if i have a name_ attribute defined in the Core Data model, then i add

var name: String { 
  get { name_ ?? "No Name" }
  set { name_ = newValue }
}

as an extension to the entity, and now i can freely write myObject.name throughout SwiftUI views and not have to continually nil-coalesce everything when i use it.

you might want to check out my "build and fail in public" ShoppingList16 app, which is where i found this problem back in iOS 13, and i have not had crashes with this strategy after finding out what was happening. there's plenty of commentary in the source code on this very point.

hope that helps,

DMG

@DelawareMathGuy Thanks for the detailed reply. Although i could nil-coalesce every single access to a Core Data property in the SwiftUI views, doing so for more than a handful of properties seems impractical. A lot of the properties are not marked optional (model and class), making this approach more challenging.

i could change the NSManagedObject subclasses so properties are optional, but there is a sizable non-UI portion of the App that makes heavy use of Core Data; changing the optionality of properties would result in a lot of re-work.

Again, thanks for the reply. i will checkout the App you linked to, it might give me insights that prove helpful.