循环函数中的异步调用。仅在异步完成时返回

Posted

技术标签:

【中文标题】循环函数中的异步调用。仅在异步完成时返回【英文标题】:Async call in loop func. Return only when async finished 【发布时间】:2016-12-08 10:43:12 【问题描述】:

我有一个 Alamofire 调用,我在其中获取项目列表,然后解析它们:

class func getList(_ completion:@escaping (Array<Item>) -> Void) 
    Alamofire.request("http://foo.com", method: .get, parameters: nil, headers: nil)
       .responseJSON  response in
           let list = parseList(response as! NSArray)
           completion(list)
    

当我解析列表时,我需要再次调用以获取项目的状态:

class func parseList(_ responseArray: NSArray) -> Array<Item> 
    let list = NSMutableArray()
    for itemDic in responseArray 
        let item  = Item()
        item.id   = itemDic.value(forKey: "Id") as? Int
        item.name = itemDic.value(forKey: "Name") as? Int

        Alamofire.request("http://bar.com", method: .get, parameters: nil, headers: nil)
           .responseJSON  response in
               item.status = response as? String
        
        list.add(item)
    
    return list as NSArray as! Array<Item>

主要问题是我需要在第一个函数中完成之前获得所有项目状态,现在当循环已经返回数组时我会得到一些状态响应。返回带有状态的解析列表的最佳解决方案是什么?

【问题讨论】:

使用 dispatch group 和 dispatch_group_wait 调用completjon(list) 【参考方案1】:

将解析函数更改为闭包并添加 DispatchGroup 直到设置所有状态。

第一个函数:

class func getList(_ completion:@escaping (Array<Item>) -> Void) 
    Alamofire.request("http://foo.com", method: .get, parameters: nil, headers: nil)
       .responseJSON  response in
           self.parseList(response as! NSArray, completion:  (list) in
               completion(list)
           )
    

第二个功能:

class func parseList(_ responseArray: NSArray, completion:@escaping(Array<Item>) - Void) 
    let dispatch = DispatchGroup()
    let list     = NSMutableArray()
    for itemDic in responseArray 
        let item  = Item()
        item.id   = itemDic.value(forKey: "Id") as? Int
        item.name = itemDic.value(forKey: "Name") as? Int
        dispatch.enter()
        Alamofire.request("http://bar.com", method: .get, parameters: nil, headers: nil)
           .responseJSON  response in
               item.status = response as? String
               dispatch.leave()
        
        list.add(item)
    
    dispatchGroup.notify(queue: DispatchQueue.main) 
        completion(list as NSArray as! Array<Item>)
    

【讨论】:

【参考方案2】:

你可以使用一个简单的循环计数器来实现你想要的......

class func getList(_ completion:@escaping (Array<Item>) -> Void) 
    Alamofire.request("http://foo.com", method: .get, parameters: nil, headers: nil)
       .responseJSON  response in
           let list = parseList(response as! NSArray)
           completion(list)
    

从这里我修改了你的一些代码...我声明了一个计数器来确定何时抛出带有状态项的完整列表的回调。

class func parseList(_ responseArray: NSArray, _ completion: @escaping (Array<Any>) -> Void) 
    let list = NSMutableArray()
    let counter: Int = 0 // counter

    for itemDic in responseArray 
        let item  = Item()
        item.id   = itemDic.value(forKey: "Id") as? Int
        item.name = itemDic.value(forKey: "Name") as? Int

        Alamofire.request("http://bar.com", method: .get, parameters: nil, headers: nil)
           .responseJSON  response in
               item.status = response as? String

               list.add(item) // when the alamofire return the call we set the status then add it to our list..
               counter += 1 // then increment our counter

                // here ... we verify if the counter matches the total count of the item we need need to fetch
                if responseArray.count == counter 
                    completion(list) // if it matches the total count then we will fire the callback with the list of the item with statuses.
                
        
    

【讨论】:

以上是关于循环函数中的异步调用。仅在异步完成时返回的主要内容,如果未能解决你的问题,请参考以下文章

循环内的异步函数完成后如何调用函数?

在 for 循环中的异步函数调用中有条件地执行回调

全局调用异步函数时出错:“等待仅在异步函数和模块的顶层主体中有效”?

AngularJS仅在父控制器完成异步调用时加载控制器

当for内部有查询时如何返回异步函数的值

当循环中调用了异步函数时,Node.JS 将如何处理循环控制?