如何等到来自网络调用的数据到来,然后才返回函数#Swift的值



我有一个服务类,它进行api调用并将数据存储到其属性中。然后我的interator类有一个方法,我想在这里调用服务类api,以及何时存储数据-返回它。我试着用完成处理程序和调度组来处理这个问题,但(我想我只是错过了一些东西(这不起作用。如果你能帮我处理这个问题,我将不胜感激。提前感谢!

服务类别:

class PunkApiService{
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
}
do{
let beers = try JSONDecoder().decode([Beer].self, from: data)
self.beers.append(contentsOf: beers)
}
catch{
print("Failed to decode data")
}
}
task.resume()
}

和交互程序类(没有完成处理程序或调度组(:

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
}

添加:我尝试使用完成处理程序

var beers: [Beer]                                          
func loadList(at page: Int, completion: ()->()){
service.loadList(at: page)
completion()

}
func completion(){
beers.append(contentsOf: service.beers)
}
loadList(at: 1) {
completion()
}

这就是async/await模式的作用,在这里进行了描述。在您的情况下,两个loadList函数都是async,第二个awaits用于第一个:

class PunkApiService {
func loadList(at page: Int) async { 
// change function to await for task result 
let (data, error) = try await URLSession.shared.data(from: url)
let beers = try JSONDecoder().decode([Beer].self, from: data)
...
return beers
}
}
class BeersListInteractor: BeersListInteractorProtocol {
func loadList(at page: Int) async -> [Beer]{
let beers = await service.loadList(at: page)
return service.beers
}
}

在这里看到一个很好的解释

我认为您在尝试使用完成块时走的是正确的道路,只是没有正确执行。

func loadList(at page: Int, completion: @escaping ((Error?, Bool, [Beer]?) -> Void)) {
//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")
completion(nil, false, nil)
return
}
//MARK: - Creating URLSession DataTask
let task = URLSession.shared.dataTask(with: url){ data, response, error in
//MARK: - Handling no erros came
if let error = error {
completion(error, false, nil)
print(error!)
return
}
//MARK: - Handling data came
guard let data = data, let beers = try? JSONDecoder().decode([Beer].self, from: data) else { 
completion(nil, false, nil)
return
}
completion(nil, true, beers)
}
task.resume()
}

这是loadList函数,它现在有一个completion参数,它将有三个参数,分别是可选的Error、代表获取数据成功或失败的Bool值和包含数据(如果检索到任何数据(的实际[Beers]数组。

以下是您现在如何调用函数:

service.loadList(at: page) { error, success, beers in
if let error = error {
// Handle the error here
return
}
if success, let beers = beers {
// Data was correctly retrieved - and safely unwrapped for good measure, do what you need with it
// Example:
loader.stopLoading()
self.datasource = beers
self.tableView.reloadData()
}
}

请记住,完成是异步执行的,而不会停止应用程序其余部分的执行。此外,您应该决定是直接在loadList函数内部还是在闭包内部处理错误,如果在函数内部处理,则可能会删除Error参数。其他参数也是如此:您可以决定只有一个只有[Beer]参数的闭包,并且只有在正确检索和转换数据的情况下才能调用闭包。

相关内容

最新更新