1

Is it possible to lazy load images that I have stored on a local database stored as Data?

Image(uiImage: UIImage(data: realm.imageData) ?? UIImage(named: "NotFound")!)

The computing of UIImage(data: realm.imageData) makes switching to and from this tab slow.

This is user inputted images into the database so the range of images could be from 0 to a lot.

(hopefully) minimum reproducible code

struct ContentView: View {
    
    var dataArr: [Data] = []
    
    var body: some View {
        
        ForEach(dataArr, id: \.self) { imageData in
            Image(uiImage: UIImage(data: imageData) ?? UIImage(named: "NotFound")!)
        }
    }
}

The problem is that all the processing is happening on tab switch instead of on appear.

note: these images are generated on device and and there is no reference to the URL. it has to be stored as data.

5
  • 1
    In general, Realm is not a good datastore for images. There's a hard limit to the size of a single property (16Mb) and images can easily go well beyond that. Please see my answer here for more in depth info. If the images are small, thumbnails for example, that would work and you should not really see any performance issues. One issue is using the Array to store realm objects. Please use @ObservedResults to properly work with them instead. Commented Nov 23, 2022 at 18:06
  • @Jay that was all great information and a pleasure to read. I am using everything listed. seems like using ForEach instead of List was causing the poor performance. Commented Nov 24, 2022 at 1:46
  • - I am using everything listed - well, you're not. This var dataArr: [Data] = [] is what I was referring to; it overrides Realms lazy-loading nature and ALL of the data stored in that array is loaded into memory which is likely associated with the performance issue. Use ObservedResults instead. The is no issue using ForEach within a List. See this example Commented Nov 24, 2022 at 14:12
  • sorry, this code sample was just minimum reproducible code. In my actual code, I am using ObservedResults. Commented Nov 24, 2022 at 20:42
  • Thanks for that info. As you can see, answers and comments are based on the data in the question; we're only as good as what's given to us ;-). Not posting your code sends us down the wrong path. Can you update the question with your actual code so we can better understand the issue? Commented Nov 25, 2022 at 14:56

1 Answer 1

2

In general, Realm is not a good datastore for images.

There's a hard limit to the size of a single property (16Mb) and images can easily go well beyond that. Please see my answer here for more in depth info.

If the images are small, thumbnails for example, that would work and you should not really see any performance issues.

The main issue I see in the question is using the Array to store realm objects.

var dataArr: [Data] = [] //Dont do this

With Array's, Realm loses its lazy-loading nature and all of the objects are crammed into memory - that can overwhelm the device quickly if the images are large. It can also affect app performance and UI responsiveness.

The other downside is that it disconnects the grouping of objects from their underlying data. For example, suppose the app displays images of users and a new user signs up. With the array, the app will not be aware of that change.

Please use @ObservedResults to properly work with Realm objects instead.

There are many benefits; the objects continue to be lazily loaded, it implicitly opens the Realm and retrieves the objects, it's a live reflection of those objects and it makes writing simpler as well. Also, if the data is filtered as users are added, changed or removed, the Results stay aligned and the UI can be updated.

If the object looked like this

class ImageObject: Object {
  @Persisted var imageData: Data
  ...

The code would be something like this

@ObservedResults(ImageObject.self) var imageObjectResults

    var body: some View {
        NavigationView {
            VStack {
                List {
                    ForEach(imageObjectResults) { anImageObject in
                        let theData = anImageObject.imageData
                        //do something with theData
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.