快速同步多个Web服务调用 [英] Synchronise multiple web service calls in serial order in swift

查看:95
本文介绍了快速同步多个Web服务调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要访问一个Web服务URL十次,并得到响应.我正在使用AlamofireSwiftyJSON.这是我的控制器代码

I am hitting a web service url 10 times and getting the response. I am using Alamofire and SwiftyJSON. This is my controller code

class ViewController: UIViewController {

    let dispatchGroup = DispatchGroup()

    var weatherServiceURL = "http://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22"

    override func viewDidLoad() {
        super.viewDidLoad()
        start()
    }

    func start() {
        weatherService()
        dispatchGroup.notify(queue: .main) {
            print("All services complete")
        }
    }

    func weatherService() {
        for i in 1...10 {
            dispatchGroup.enter()
            APIManager.apiGet(serviceName: self.weatherServiceURL, parameters: ["counter":i]) { (response:JSON?, error:NSError?, count:Int) in
                if let error = error {
                    print(error.localizedDescription)
                    return
                }
                guard let response = response else { return }
                print("\n\(response) \n\(count) response\n")
                self.dispatchGroup.leave()
            }
        }
    }
}

这是我的服务处理程序类代码

This is my Service Handler class code

class APIManager: NSObject {

    class func apiGet(serviceName:String,parameters: [String:Any]?, completionHandler: @escaping (JSON?, NSError?, Int) -> ()) {
        Alamofire.request(serviceName, method: .get, parameters: nil, encoding: URLEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in

            switch(response.result) {
            case .success(_):
                if let data = response.result.value{
                    let json = JSON(data)
                    completionHandler(json,nil, parameters!["counter"] as! Int)
                }
                break

            case .failure(_):
                completionHandler(nil,response.result.error as NSError?, parameters!["counter"] as! Int)
                break
            }
        }
    }
}

我正在发送带有for循环索引的计数器密钥,只是为了跟踪返回哪个索引的响应.但是响应不是按顺序进行的.我们可以期望在第二和第一响应之前有第三响应.这是因为带有APIManager.apiGet函数调用的API调用是异步的,正在转义,因此继续进行for循环.

I am sending a counter key with the index of for loop just to keep the track of response of which index is coming back. But the response is not coming in serial order. We can expect 3rd response before the 2nd and 1st response. This is because the API call with APIManager.apiGet function call is asynchronous and is escaping and therefore continuing the for loop.

我也使用了dispatchQueue

Also I used the dispatchQueue

let dispatchQueue = DispatchQueue(label: "com.test.Queue", qos: .userInteractive)

并将函数转换为:

func weatherService() {
    for i in 1...10 {
        dispatchGroup.enter()
        dispatchQueue.async {
            APIManager.apiGet(serviceName: self.weatherServiceURL, parameters: ["counter":i]) { (response:JSON?, error:NSError?, count:Int) in
                if let error = error {
                    print(error.localizedDescription)
                    return
                }
                guard let response = response else { return }
                print("\n\(response) \n\(count) response\n")
                self.dispatchGroup.leave()
            }
        }
    }
}

与服务调用代码异步的结果相同.如果我们做

Same result as the service calling code is asynchronous. If we make

dispatchQueue.sync {
   //service call 
}

然后,由于async和dispatchQueue中的网络调用假定任务已完成,因此我们也不会按顺序获得响应.

then also we will not get the response in serial order since the networking call in async and dispatchQueue assumes the task is completed.

条件是仅在不冻结UI的情况下以异步方式运行服务.如果我以同步方式运行服务,那么我会得到理想的结果.但是阻塞主线程是根本不可接受的.

Condition is to hit the service in async manner only without freezing the UI. If I hit the service is synchronous manner, then I get my desired result. But blocking main thread is not at all acceptable.

我可以使用数组或某些全局bool变量来管理此事,但我不想使用它们.还有什么其他方法可以让我以被称为的串行顺序获得响应?任何帮助或提示,我们感激不尽.

I can manage this thing using array or some global bool variables, but I don't want to use them. Is there any other way I can get response in serial order in which it is called? Any help or hint is appreciated.

推荐答案

解决方案:使用DispatchSemaphore s和DispatchQueue

Solution: Use DispatchSemaphores and a DispatchQueue

我决定不保存闭包,而是决定将所有内容包装在分派队列中并在其中使用信号量

Rather than saving the closures, I decided to wrap everything up in a dispatch queue and use semaphores inside it

//Create a dispatch queue 
let dispatchQueue = DispatchQueue(label: "myQueue", qos: .background)

//Create a semaphore
let semaphore = DispatchSemaphore(value: 0)

func weatherService() {

    dispatchQueue.async {
        for i in 1...10 {
            APIManager.apiGet(serviceName: self.weatherServiceURL, parameters: ["counter":i]) { (response:JSON?, error:NSError?, count:Int) in
                if let error = error {
                    print(error.localizedDescription)
                    self.semaphore.signal()
                    return
                }
                guard let response = response else { 
                    self.semaphore.signal()
                    return 
                }

                print("\(count) ")

                //Check by index, the last service in this case
                if i == 10 {
                    print("Services Completed")
                } else {
                    print("An error occurred")
                }

                // Signals that the 'current' API request has completed
                self.semaphore.signal()
            }

            // Wait until the previous API request completes
            self.semaphore.wait()
        }
    }
    print("Start Fetching")
}

输出始终是

Output is this always

这篇关于快速同步多个Web服务调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆