0

I created a custom view, NetworkImage, to load image asynchronously.

import Combine
import SwiftUI

struct NetworkImage<Placeholder: View>: View {
    @StateObject private var viewModel = NetworkImageViewModel()
    let url: String?
    let placeholder: Placeholder
    let saveLocally:Bool
    
    init(_ url: String?, @ViewBuilder placeholder: () -> Placeholder, saveLocally:Bool = false) {
        self.url = url
        self.placeholder = placeholder()
        self.saveLocally = saveLocally
    }
    
    func loadImage(_ url:String?)  {
        if let url = url {
            viewModel.loadImage(from: url, saveLocally: saveLocally)
        }
    }
    
    var body: some View {
        Group {
            if let uiImage = viewModel.image {
                Image(uiImage: uiImage)
                    .resizable()
            } else {
                placeholder
            }
        }
        .onAppear {
            if let url = url {
                viewModel.loadImage(from: url, saveLocally: saveLocally)
            }
        }
    }
}

I use this in my views and it works really well. But now I would like to be able to replace the image with a new one each time the url change. How can I do that? How can I pass a @Published property of my view's viewmodel to this NetworkImage view and make it work?

Thanks

Edwin ZAP
  • 419
  • 1
  • 4
  • 16

1 Answers1

1

Use the onChange modifier to see if the url parameter has changed:

struct NetworkImage<Placeholder: View>: View {
    @StateObject private var viewModel = NetworkImageViewModel()
    let url: String?
    let placeholder: Placeholder
    let saveLocally:Bool = false
    
    func loadImage(_ url:String?)  {
        if let url = url {
            viewModel.loadImage(from: url, saveLocally: saveLocally)
        }
    }
    
    var body: some View {
        Group {
            if let uiImage = viewModel.image {
                Image(uiImage: uiImage)
                    .resizable()
            } else {
                placeholder
            }
        }
        .onAppear {
            self.loadImage(url)
        }
        .onChange(of: url) { url in
            self.loadImage(url)
        }
    }
}
jnpdx
  • 45,847
  • 6
  • 64
  • 94
  • Thanks. Just one thing I don't understand: this does not work if I use the value of self.url in loadImage(). Same for self.saveLocally. I would like to listen to changes of the saveLocally and use it with loadImage(url, saveLocally) but the value of saveLocally does not change at the right time (seems a bit random) – Edwin ZAP Jul 29 '21 at 20:33