How to call the api in SwiftUI and Combine ios project.
1. ContentView
import SwiftUI
struct ContentView: View {
//We need @ObservedObject to observe ViewModel class
@ObservedObject
var viewModel = ViewModel()
var body: some View {
VStack {
//List is rerendered whenever ViewModel's characters property changed
List(viewModel.characters) { character in
CharacterRow(character: character)
}
}
.padding()
.onAppear {
//this closure is executed before View appears
viewModel.fetchCharacters()
}
}
}
2. CharacterRow
import SwiftUI
struct CharacterRow: View {
var character: Character
var body: some View {
HStack {
AsyncImage(url: character.image) { image in
image
.resizable()
.clipShape(RoundedRectangle(cornerRadius: /*@START_MENU_TOKEN@*/25.0/*@END_MENU_TOKEN@*/, style: .continuous))
.frame(width: 100, height: 100)
} placeholder: {
ProgressView()
}
Text(character.name)
}
}
}
3. Character struct and CharacterResponse struct
import Foundation
struct CharacterResponse: Codable {
let results: [Character]
}
struct Character: Codable, Identifiable {
let id: Int
let name: String
let image: URL
}
I receive api response using these structs
4. ViewModel
import Foundation
import Combine
class ViewModel : ObservableObject {
//@Published make the view re-render whenever characters changes
@Published var characters: [Character] = []
var subscriptions = Set<AnyCancellable>()
func fetchCharacters() {
guard let url = URL(string: "https://rickandmortyapi.com/api/character") else {return}
URLSession.shared.dataTaskPublisher(for: url)
.map {
$0.data
}.decode(type: CharacterResponse.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
switch completion {
case .failure(let error):
print(error.localizedDescription)
case .finished:
print("Data Fetched")
}
}, receiveValue: { decodedData in
print("receiveValue, count: \(decodedData.results.count)")
self.characters = decodedData.results
})
.store(in: &subscriptions)
}
}
댓글 없음:
댓글 쓰기