Search code examples
iosswiftuicore-data

How to update CoreData entries when an array is used to originally save the data, but isn’t actually an attribute in the Entity


My question boils down to: how to update CoreData entries when an array is used to originally save the data, but isn’t actually an attribute in the Entity.

I’ll explain:

Today, I can edit a CoreData object using @ObservedObject like this:

enter image description here

This makes sense to me because each item I’m looking to update exists as an attribute to the CoreData Entity.

However, I’ve updated my Project entity to have an inverse relationship with a new Entity: CapturedImage using the relationship capturedimages

enter image description here

enter image description here

In this new setup, instead of saving 4 individual images to Project image1, image2, image3, and image4, I’m now saving images to CapturedImage, where @State var images: [Data] = []

enter image description here

This works great for allowing me to not have to pre-determine how many images the user might want to save. Then I can display the images using a ForEach.

Here’s the question

I’m stuck trying to figure out how to create an Edit view using this new setup. Since images is not an attribute stored in my Project Entity, and is only used to temporarily hold the array of images when creating the object, I don’t know how to satisfy the initializer. So far every attempt to initialize it has failed.

enter image description here

Thanks so much!

[EDIT 1]
After breaking it down some more, I think the issues lies with how I’m initializing

self._capturedimages = State(wrappedValue: ([project.capturedimages] as? [Data] ?? [capturedimages]))

And that instead of referring to images in the view, I should be referring to capturedimages

The error I get is "Cannot convert value of type '[Data]?' to expected element type 'Array.ArrayLiteralElement' (aka 'Data’)” … So I think it’s that last part, the [capturedimages] that I can’t quite get right.


Solution

  • In SwiftUI you shouldn't init objects in View struct inits. The reason is that these View structs are just lightweight values that are created and thrown every time there is a state change in the parent and the parent's body re-inits the View struct. Initing an object inside a View struct is basically a memory leak. That is why we have @StateObject property wrapper that will only init the object once - right before body is called (not just if init was called) but that is for a different purpose entirely.

    You need to re-architect so that the Project managed object is init in an action, e.g. a button handler or an an @State optional struct init or in a mutating func in a @State struct that you call from a button handler.

    For ideas, you could take a look at this CoreDataBooks-SwiftUI example I created.