I write my project in SwiftUI with VIPER pattern, and i stucked a little bit with this problem. You can see that i call a function of presenter in a view when list appear. This function calls function of interactor and in this function calling service function. The problem is that service don't have time to return data and interactors function returns empty array. How to order code execution using GCD in such order : service function -> interactor function -> presenter function. Thanks in advance !
class PunkApiService:ObservableObject{
@Published var beers = [Beer]()
func loadList(at page: Int) {
//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()
print(beers)
}
}
class BeersListInteractor:BeersListInteractorProtocol{
private var favoriteBeers = FavoriteBeers()
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)
}
}
}
}