检查Alamofire和Swift中的多个异步响应

12

我正在编写一个应用程序,该应用程序依赖于来自各个站点/服务的数据,并涉及基于这些不同来源的数据执行计算以生成最终产品。

我编写了一个示例类,其中包含两个函数,从两个不同的来源收集数据。 我选择使这两个函数不同,因为有时我们会根据来源应用不同的身份验证方法,但在此示例中,我仅将它们简化为最简单的形式。 这两个函数都使用Alamofire启动和处理请求。

然后我有一个初始化函数,如果成功从两个来源收集数据,则加载另一个nib文件,否则等待最多四秒钟,如果没有返回响应,则加载一个服务器错误nib文件。

我尽可能地让这个示例变得简单。 基本上,这是我想要遵循的逻辑。 不幸的是,目前的实现方式似乎不能正常工作。

import Foundation

class GrabData{
    var data_source_1:String?
    var data_source_2:String?

    init(){    
        // get data from source 1
        get_data_1{ data_source_1 in
            println("\(data_source_1)")
        }

        // get data from source 2
        get_data_2{ data_source_1 in
            println("\(data_source_1)")
        }

        var timer = 0;
        while(timer<5){
            if((data_source_1 == nil) && (data_source_2 == nil)){
                // do nothing unless 4 seconds has elapsed
                if (timer == 4){
                    // load server error nib
                }
            }else{
                // load another nib, and start manipulating data
            }
            // sleep for 1 second
            sleep(1)
            timer = timer+1
        }    
    }

    func get_data_1(completionHandler: (String) -> ()) -> () {
        if let datasource1 = self.data_source_1{
            completionHandler(datasource1)
        }else{
            var url = "http://somewebsite.com"
            Manager.sharedInstance.request(.GET, url).responseString {
                (request, response, returnedstring, error) in
                println("getting data from source 1")
                let datasource1 = returnedstring
                self.data_source_1 = datasource1
                completionHandler(datasource1!)
            }
        }
    }

    func get_data_2(completionHandler: (String) -> ()) -> () {    
        if let datasource2 = self.data_source_2{
            completionHandler(datasource2)
        }else{
            var url = "http://anotherwebsite.com"
            Manager.sharedInstance.request(.GET, url).responseString {
                (request, response, returnedstring, error) in
                println("getting data from source 2")
                let datasource2 = returnedstring
                self.data_source_2 = datasource2
                completionHandler(datasource2!)
            }
        }
    }
}

我知道我可以将第二个闭包放在init函数内部的第一个闭包中,但是我认为这不是最佳实践,并且我实际上是从超过2个源头提取数据,因此闭包将有n层深度。

如果有帮助来找出检查多个数据源是否给出有效响应的最佳方法,并适当地处理它,将不胜感激。

1个回答

48

相较于那个会阻塞线程的循环过程,你可以使用调度组来跟踪请求何时完成。因此,在发布每个请求之前「进入」该组,在请求完成后「离开」该组,并设置一个「通知」块/闭包,在组中的所有任务都完成时调用它。

例如,在Swift 3中:

let group = DispatchGroup()

group.enter()
retrieveDataFromURL(url1, parameters: firstParameters) {
    group.leave()
}

group.enter()
retrieveDataFromURL(url2, parameters: secondParameters) {
    group.leave()
}

group.notify(queue: .main) {
    print("both requests done")
}

或者在Swift 2中:

let group = dispatch_group_create()

dispatch_group_enter(group)
retrieveDataFromURL(url1, parameters: firstParameters) {
    dispatch_group_leave(group)
}

dispatch_group_enter(group)
retrieveDataFromURL(url2, parameters: secondParameters) {
    dispatch_group_leave(group)
}

dispatch_group_notify(group, dispatch_get_main_queue()) {
    print("both requests done")
}

另一种方法是将这些请求封装在异步的NSOperation子类中(使它们可以被取消,您可以控制并发程度的限制等),但这更加复杂,因此您可能希望像上面展示的那样从调度组开始。


我需要异步方法。 - famfamfam
@famfamfam - 如果你想要一个异步方法,你可以将上述调度组与一些完成处理程序或其他异步模式结合起来,例如:https://gist.github.com/robertmryan/f8fbd368f1ec94e0bbf8a5b787bc0fef - Rob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接