Skip to content

Instantly share code, notes, and snippets.

@glzawalski
Last active December 5, 2023 12:19
Show Gist options
  • Save glzawalski/4792c723cd1fb8be7771c1aee909d070 to your computer and use it in GitHub Desktop.
Save glzawalski/4792c723cd1fb8be7771c1aee909d070 to your computer and use it in GitHub Desktop.
Basic ContentView loading data with async/await
//
// ContentView.swift
// FetchAsync
//
// Created by Gabriel Zawalski on 09/11/23.
//
import SwiftUI
struct ContentView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
List(viewModel.users) { user in
Text(user.name)
}
// Modificador de task realiza a chamada do método dentro do callback antes da view aparecer em tela
// Se quiser um método após a tela já renderizada pode usar o onAppear com uma Task dentro
// .onAppear {
// Task {
// await viewModel.fetchData
// }
// }
// Se sua variável fosse um estado local o método fetchData pode retornar um valor e ser atribuído aqui sem problemas
.task {
await viewModel.fetchData()
}
}
}
#Preview {
ContentView(viewModel: ViewModel())
}
class ViewModel: ObservableObject {
// Quando essa variável é atualizada ela emite eventos para os listeners dela
// Permitindo que atualize as views que estão escutando por esses valores
@Published var users = [User]()
let userUseCase = UserUseCase()
func fetchData() async {
users = await userUseCase.fetchUsers()
}
}
class UserUseCase {
let networkService = NetworkService()
func fetchUsers() async -> [User] {
// Para URLs conhecidas e fixadas tudo bem fazer force unwrap
// Uma idéia melhor para casos reais seria usando guard let
// guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else {
// return // Seu tratamento em caso de falha aqui
// }
let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
return await networkService.fetch(url: url)
}
}
class NetworkService {
func fetch<Model>(url: URL) async -> [Model] where Model: Decodable {
do {
// Retorno desse método é a tupla (Data, Request), por isso fazemos bind só do primeiro parâmetro
let (data, _ ) = try await URLSession.shared.data(from: url)
let decodedData = try JSONDecoder().decode([Model].self, from: data)
return decodedData
} catch {
return [] // Aqui viria o tratamento de erro no caso de falha para o try acima
}
}
}
// Pode adicionar o protocolo Identifiable aqui para ter conformidade com lista de forma automática sem passar o \.id
// Identifiable requer que você tenha um id de qualquer valor que seja único para seus dados
// assim a lista sabe se organizar e quais valores mudaram ou não
struct User: Decodable, Identifiable {
let id: Int
let name: String
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment