swift 以串行顺序同步多个 Web 服务调用

Raj*_*ari 2 grand-central-dispatch ios dispatch-async swift dispatchworkitem

我点击了 10 次 Web 服务 url 并得到响应。我正在使用AlamofireSwiftyJSON。这是我的控制器代码

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()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在发送一个带有 for 循环索引的计数器键,只是为了跟踪哪个索引返回的响应。但是响应不是按顺序来的。我们可以在第 2 次和第 1 次响应之前期待第 3 次响应。这是因为带有APIManager.apiGet函数调用的 API 调用是异步的并且正在转义,因此会继续 for 循环。

我也使用了 dispatchQueue

let dispatchQueue = DispatchQueue(label: "com.test.Queue", qos: .userInteractive)
Run Code Online (Sandbox Code Playgroud)

并将函数转换为:

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()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

dispatchQueue.sync {
   //service call 
}
Run Code Online (Sandbox Code Playgroud)

那么我们也不会以串行顺序获得响应,因为 async 和 dispatchQueue 中的网络调用假设任务已完成。

条件是仅以异步方式访问服务而不冻结 UI。如果我打的服务是同步方式,那么我得到了我想要的结果。但是阻塞主线程是完全不能接受的。

我可以使用数组或一些全局 bool 变量来管理这个东西,但我不想使用它们。有没有其他方法可以按调用顺序获得响应?任何帮助或提示表示赞赏。

Raj*_*ari 5

解决方案:使用DispatchSemaphores 和 aDispatchQueue

我没有保存闭包,而是决定将所有内容都包装在一个调度队列中并在其中使用信号量

//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")
}
Run Code Online (Sandbox Code Playgroud)

输出总是这样

在此处输入图片说明