article

Tuesday, October 26, 2021

SwiftUI Perform Network Requests to load json data from URL

SwiftUI Perform Network Requests to load json data from URL

Json : https://picsum.photos/v2/list

ContentView.swift
 
//
//  ContentView.swift
//  Swiftuitest
//
//  Created by Cairocoders
//

import SwiftUI

struct ContentView: View {
    
    @ObservedObject var items = Remote(url: URL(string: "https://picsum.photos/v2/list")!, transform: {
        try? JSONDecoder().decode([Photo].self, from: $0)
    })
    
    var body: some View {
        
        NavigationView {
            if items.value == nil {
                ProgressView()
                    .onAppear {
                        items.load()
                    }
            }else {
                List {
                    ForEach(items.value!) { photo in
                        NavigationLink(
                            destination:
                                PhotoView(photo.download_url),
                            label: {
                                Text(photo.author)
                            })
                    }
                }.navigationTitle("Authors")
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}
Model.swift
 
//
//  Model.swift
//  Swiftuitest
//
//  Created by Cairocoders
//

import Foundation

struct Photo: Codable, Identifiable {
    let id: String
    let author: String
    let width, height: Int
    let url, download_url: URL
}

struct PhotoLoadingError: Error {}
//View Model
final class Remote<Asc>: ObservableObject {
    @Published var result: Result<Asc, Error>? = nil
    var value: Asc? { try? result?.get()}
    let url:URL
    let transform: (Data) ->Asc?
    
    init(url: URL, transform: @escaping (Data) ->Asc?) {
        self.url = url
        self.transform = transform
    }
    
    func load() {
        URLSession.shared.dataTask(with: url) { (data, _, _) in
            DispatchQueue.main.async {
                if let d = data, let v = self.transform(d) {
                    self.result = .success(v)
                } else {
                    self.result = .failure(PhotoLoadingError())
                }
            }
        }.resume()
    }
}
PhotoView.swift
 
//
//  PhotoView.swift
//  Swiftuitest
//
//  Created by Cairocoders
//

import SwiftUI

struct PhotoView: View {
    @ObservedObject var image: Remote<UIImage>
    
    init(_ url: URL) {
        self.image = Remote(url: url, transform: {
            UIImage(data: $0)
        })
    }
    
    var body: some View {
        
        Group {
            if image.value == nil {
                ProgressView()
                    .onAppear { image.load() }
            } else {
                Image(uiImage: image.value!)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
            }
        }
    }
}

Related Post