CoreData Relationship and Show the list of image in Swiftui

440 Views Asked by At

I tried to store a list of images in CoreData, using relationship of entities.

The model are designed like this: enter image description here enter image description here

When add the data, I tried to code like this:

let imageData1 = UIImage(imageLiteralResourceName: "Dummy1").jpegData(compressionQuality: 1)
let imageData2 = UIImage(imageLiteralResourceName: "Dummy2").jpegData(compressionQuality: 1)
                
newItem.addToItemImages(NSSet(array: [imageData1!, imageData2!]))
                    
try? self.viewContext.save()

After that, I would like to retrieve them through SwiftUI, but I failed to do so:

    ForEach(Array(self.item.itemImages! as! Set), id:\.self) {image in
            Image(uiImage: image)
                .frame(width: 300, height: 300)
        }

It complains unable to infer type of 'image' in the current context.

My question here:

  1. what is the proper way to store sequence of images in CoreData. Is that my current approach fine? My current approach is 1 (item) to many (ItemImage) relationship. The ItemImage has a field named 'image' which is Binary Data type.

  2. Is that my approach to store the ItemImage proper?

  3. How can I get all the ItemImage (NSSet) from item, and then display using Image() of Swiftui?

2

There are 2 best solutions below

0
Ely On

You must first make records of type ItemImage, and assign the image to the image attribute of each record. Then you can use the generated addToItemImages function to add these records to the itemImages relation of an Item record.

0
mmklug On

Your entities seem to set up ok; I would only change the Delete Rule for the itemImages relationship in the Item entity to Cascade to avoid orphan ItemImages in the database.

To add images, you need to create instances of ItemImage first and then set the relationship to an Item. This could be done in one block as follows:

if let imageData = UIImage(named: "Dummy1")?.jpegData(compressionQuality: 0.85) {
    let image = ItemImage(context: moc)
    image.id = UUID()
    image.image = imageData
    image.ofItem = item
}

Your attempt of retrieving the images is not working because of two different reasons:

First: the compiler does not know that item.itemImages is a Set of ItemImage. The automatic generated code declares itemImages as

@NSManaged public var itemImages: NSSet?

So you need to provide this information in your code by casting to Set<ItemImage> instead of simply to Set. You could avoid this by changing the declaration of itemImages to:

@NSManaged public var itemImages: Set<ItemImage>?

Second: the elements of your set are of type ItemImage (and not UIImage), so in your code you need to call Image(uiImage: UIImage(data: image.image!)!) to create an Image (i.e creating an UIImage from the data contained in the image attribute of the ItemImage object). The updated code (keeping the many force unwraps I would personally not use in my own code) would look like this:

ForEach(Array(item.itemImages! as! Set<ItemImage>)) { image in
    Image(uiImage: UIImage(data: image.image!)!)
        .resizable()
        .aspectRatio(contentMode: .fit)
        .frame(maxWidth: 300, maxHeight: 300)
}

If you change the declaration of itemImages as described above this could be simplified to

ForEach(Array(item.itemImages!)) { image in
    ...
}