I write my project with SwiftUI using VIPER pattern, and i’m stuck a little bit with this problem. My problem is (as I suppose) is that Interactor function loadList calls service function, which is network task and it takes some time to finish it, and services’ function don’t have time to finish it work so Interactor function return empty array. I’m not understand how to tell my code “wait until data come and then return value”. Here is my full data path. Thanks in advance!
class PunkApiService:ObservableObject{
@Published var beers = [Beer]()
func loadList(at page: Int)async{
//MARK: - Checks is URL is valid + pagination
guard let url = URL(string: "https://api.punkapi.com/v2/beers?page=\(page)&per_page=25") else {
print("Invalid URL")
return
}
//MARK: - Creating URLSession DataTask
let task = URLSession.shared.dataTask(with: url){ data, response, error in
//MARK: - Handling no erros came
guard error == nil else {
print(error!)
return
}
//MARK: - Handling data came
guard let data = data else{
print("Failed to load data")
return
}
//MARK: - Decoding data
do{
let beers = try JSONDecoder().decode([Beer].self, from: data)
//MARK: - Puting this piece of code to the main thread to update view when data is decoded
DispatchQueue.main.async {
self.beers.append(contentsOf: beers)
}
}
catch{
print("Failed to decode data")
}
}
task.resume()
}
}
class BeersListInteractor:BeersListInteractorProtocol{
private var favoriteBeers = FavoriteBeers()
@ObservedObject private var service = PunkApiService()
//MARK: - Load list of Beers
func loadList(at page: Int) -> [Beer] {
service.loadList(at: page)
return service.beers
}
class BeersListPresenter: BeersListPresenterProtocol, ObservableObject{
var interactor: BeersListInteractorProtocol
init(interactor: BeersListInteractorProtocol){
self.interactor = interactor
}
@Published var beers = [Beer]()
func loadList(at page: Int){
self.beers = interactor.loadList(at: page)
}
}
struct BeersListView: View{
@StateObject var presenter : BeersListPresenter
var body: some View {
NavigationView{
List{
ForEach(presenter.beers, id: \.id){ beer in
Text(beer.name)
}
}.onAppear{
presenter.loadList(at: 1)
}
}
}
}