0

我有一个服务类,它进行 api 调用并将数据存储到其属性中。然后我的交互器类有一个方法,我想在其中进行服务类 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()
}

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

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()
}
4

2 回答 2

0

这就是async/await模式的用途,在此处进行了描述。在您的情况下,这两个loadList函数都是s,async第二个函数是第一个函数await

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
    }
}

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

于 2021-12-16T22:10:31.173 回答
0

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

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参数,该参数将具有三个参数,分别是 optional ErrorBool表示获取数据成功或失败的值,以及[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]参数的闭包,并且只有在正确检索和转换数据时才调用该闭包。

于 2021-12-16T23:54:36.487 回答