DEV Community

Harsh Prajapat
Harsh Prajapat

Posted on

Swiftui api call and image downloading

import Foundation

struct Photo: Codable, Identifiable {
    let id: Int
    let title: String
    let url: String
}
Enter fullscreen mode Exit fullscreen mode
import Foundation
import UIKit

final class APIService {

    static let shared = APIService()

    private init() {}

    func fetchPhotos() async throws -> [Photo] {

        let url = URL(
            string: "https://jsonplaceholder.typicode.com/photos?_limit=20"
        )!

        let (data, _) = try await URLSession.shared.data(from: url)

        return try JSONDecoder().decode([Photo].self, from: data)
    }

    func downloadImage(from urlString: String) async -> UIImage? {

        guard let url = URL(string: urlString) else {
            return nil
        }

        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            return UIImage(data: data)
        } catch {
            return nil
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
import SwiftUI
import Combine

@MainActor
final class PhotoListViewModel: ObservableObject {

    @Published var photos: [Photo] = []
    @Published var isLoading = false

    func fetchPhotos() async {

        isLoading = true

        do {
            photos = try await APIService.shared.fetchPhotos()
        } catch {
            print(error.localizedDescription)
        }

        isLoading = false
    }
}
Enter fullscreen mode Exit fullscreen mode
import SwiftUI
import Combine

@MainActor
final class ImageLoader: ObservableObject {

    @Published var image: UIImage?

    func load(url: String) {

        Task {

            let downloadedImage =
            await APIService.shared.downloadImage(from: url)

            self.image = downloadedImage
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
import SwiftUI
import Combine

struct PhotoRow: View {

    let photo: Photo

    @StateObject private var loader = ImageLoader()

    var body: some View {

        HStack {

            Group {

                if let image = loader.image {

                    Image(uiImage: image)
                        .resizable()

                } else {

                    ProgressView()
                }
            }
            .frame(width: 80, height: 80)

            Text(photo.title)
                .font(.headline)
        }
        .onAppear {
            loader.load(url: photo.url)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
import SwiftUI

struct PhotoListView: View {

    @StateObject private var vm = PhotoListViewModel()

    var body: some View {

        NavigationView {

            List(vm.photos) { photo in

                PhotoRow(photo: photo)
            }
            .navigationTitle("Photos")
            .task {
                await vm.fetchPhotos()
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)