Checking for multiple asynchronous responses from Alamofire and Swift

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-17 06:36:14

问题


I am writing an application that depends on data from various sites/service, and involves performing calculations based on data from these different sources to produce an end product.

I have written an example class with two functions below that gathers data from the two sources. I have chosen to make the functions different, because sometimes we apply different authentication methods depending on the source, but in this example I have just stripped them down to their simplest form. Both of the functions use Alamofire to fire off and handle the requests.

I then have an initialisation function, which says if we have successfully gathered data from both sources, then load another nib file, otherwise wait up to for seconds, if no response has been returned, then load a server error nib file.

I've tried to make this example as simple as possible. Essentially. This is the kind of logic I would like to follow. Unfortunately it appears this does not currently work in its current implementation.

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

I know that i could put the second closure within the first inside the init function, however, I don't think this would be best practice and I am actually pulling from more than 2 sources, so the closure would be n closures deep.

Any help to figuring out the best way to checking if multiple data sources gave a valid response, and handling that appropriately would be much appreciated.


回答1:


Better than that looping process, which would block the thread, you could use dispatch group to keep track of when the requests were done. So "enter" the group before issuing each of the requests, "leave" the group when the request is done, and set up a "notify" block/closure that will be called when all of the group's tasks are done.

For example, in 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")
}

Or, in 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")
}

The other approach is to wrap these requests within an asynchronous NSOperation subclass (making them cancelable, giving you control over constraining the degree of concurrency, etc.), but that's more complicated, so you might want to start with dispatch groups as shown above.



来源:https://stackoverflow.com/questions/28100847/checking-for-multiple-asynchronous-responses-from-alamofire-and-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!