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
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)
}
}
}