Raj*_*ari 2 grand-central-dispatch ios dispatch-async swift dispatchworkitem
我点击了 10 次 Web 服务 url 并得到响应。我正在使用Alamofire和SwiftyJSON。这是我的控制器代码
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 变量来管理这个东西,但我不想使用它们。有没有其他方法可以按调用顺序获得响应?任何帮助或提示表示赞赏。
解决方案:使用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)
| 归档时间: |
|
| 查看次数: |
7548 次 |
| 最近记录: |