So I'm trying to create a content feed using data fetched from my Node.js server.
Here I fetch data from my API:
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()
}
}
Set the variables to the data fetched from the API:
final class PostListViewModel: ObservableObject {
init() {
fetchPosts()
}
@Published var posts = [Post]()
private func fetchPosts() {
Webservice().getAllPosts {
self.posts = $0
}
}
}
Post model:
struct Post: Codable, Hashable, Identifiable {
let id: String
let title: String
let path: String
let description: String
}
SwiftUI:
struct ContentView: View {
@ObservedObject var model = PostListViewModel()
var body: some View {
List(model.posts) { post in
HStack {
Text(post.title)
Image("http://localhost:8000/" + post.path)
Text(post.description)
}
}
}
}
The Text from post.title
and post.description
are displayed correctly but nothing displays from Image
. How can I use a URL
from my server to display with my image?
AsyncImage(url: URL(string: "https://your_image_url_address"))
more info on Apple developers document: AsyncImage
first you need to fetch image from url :
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) { [weak self] data, response, error in
guard let data = data, self != nil else { return }
DispatchQueue.main.async { [weak self]
self?.data = data
}
}
task.resume()
}
}
you can put this as a part of your Webservice class function too.
then in your ContentView struct you can set @State image in this way :
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()
}
}
}
Also, this tutorial is a good reference if you need more