2

I've created a simple SwiftUI application, which is displaying images from the network in the list. All images are loaded in the background. At this point, all work as expected. However, if during the load, some State variable did trigger, all my cells get re-initialized.

Let's see the code:

struct ImageView: View {

   @ObservedObject var imageLoader = ImageLoader()

   var body: some View {

        VStack {

            if self.imageLoader.isLoaded {

               DisplayImage(self.imageLoader.image)
            } else {

               Text("Loading...")
            }
        }
        .onAppear {

            self.imageLoader.loadImage()
        }
   }
}

struct TableView: View {
   
   @State var someTrigger: Bool = false;

    var body: some View {

       List {

           ForEach( someCollection, id: \.self) {

              ImageView()
           }
       }
    }
}

So, if 'someTrigger' is triggered while images are loading, all the cells will be re-initialized, imageLoader will be re-initialzed, .onAppear will not be called, the image won't load.

Is this expected behaviour? In that case, I just can't initialize my model with some background tasks that way?

Thanks in advance.

2 Answers 2

2

SwiftUI 2.0

Use instead StateObject wrapper, it will allow not recreate loader

struct ImageView: View {
   @StateObject var imageLoader = ImageLoader()

SwiftUI 1.0

Possible solution (might depend on your real code) is to make ImageView equatable by some property (eg, id only) explicitly, ie. excluding imageLoader itself. This can give chance for rendering engine to not replace ImageView on state change

For example

struct ImageView: View, Equatable {
    static func == (lhs: Self, rhs: Self) -> Bool {
        lhs.url == rhs.url
    }

    let url: URL // some unique property
    @ObservedObject var imageLoader = ImageLoader()

    // ... other code
}

and use

   ForEach( someCollection, id: \.self) {
      ImageView().equatable()       // << here !!
   }
Sign up to request clarification or add additional context in comments.

Comments

0

I think this would be solved for you by passing in the imageLoader rather than having it initialized in the view itself. I would actually recommend having the collection objects have an ImageLoader which updates some @Published image property. Try to set up the model to do all the heavy lifting and let the view just declare what it should be for each state of your model.

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.