So I'm adding an Image to my SwiftUI list by getting(fetching) the path to the image and then using the image path to fetch the image from that url/path.
Grabbing the data/path
class Webservice {
func getAllPosts(completion: @escaping ([Post]) -> ()) {
guard let url = URL(string: "http://localhost:8000/albums")
else {
fatalError("URL is not correct!")
}
URLSession.shared.dataTask(with: url) { data, _, _ in
let posts = try!
JSONDecoder().decode([Post].self, from: data!); DispatchQueue.main.async {
completion(posts)
}
}.resume()
}
}
Variables
struct Post: Codable, Hashable, Identifiable {
let id: String
let title: String
let path: String
let description: String
}
Setting the variables in Post to the posts in completion(posts) in class Webservice.
final class PostListViewModel: ObservableObject {
init() {
fetchPosts()
}
@Published var posts = [Post]()
private func fetchPosts() {
Webservice().getAllPosts {
self.posts = $0
}
}
}
Fetch image from url/path
class ImageLoader: ObservableObject {
var didChange = PassthroughSubject<Data, Never>()
var data = Data() {
didSet {
didChange.send(data)
}
}
init(urlString:String) {
guard let url = URL(string: urlString) else { return }
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { return }
DispatchQueue.main.async {
self.data = data
}
}
task.resume()
}
}
Set @State image
struct ImageView: View {
@ObservedObject var imageLoader:ImageLoader
@State var image:UIImage = UIImage()
init(withURL url:String) {
imageLoader = ImageLoader(urlString:url)
}
var body: some View {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width:100, height:100)
.onReceive(imageLoader.didChange) { data in
self.image = UIImage(data: data) ?? UIImage()
}
}
}
Then display my image in a list using ImageView with the url/path from the data I fetched in the beginning which gets passed into ImageLoader to grab the image and set @State image in ImageView
struct ContentView: View {
init() {
Webservice().getAllPosts {
print($0)
}
}
@ObservedObject var model = PostListViewModel()
var body: some View {
List(model.posts) { post in
VStack {
Text(post.title)
ImageView(withURL: "http://localhost:8000/\(post.path)")
Text(post.description)
}
}
}
}
This code works to get the image at first but once I start scrolling here and there the images start to disappear. Why is this happening and how do I fix it?
Edit: I was told to cache the images to prevent loading again. Does anyone know how I would do that?