我点击一个web服务url 10次并得到响应。我使用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()
}
}
}
}
字符串
这是我的服务级别代码
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循环。
我还使用了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()
}
}
}
}
型
与服务调用代码是异步的结果相同。
dispatchQueue.sync {
//service call
}
型
那么我们也不会以串行顺序获得响应,因为在dtoc和dispatchQueue中的网络调用假设任务已经完成。
条件是在不冻结UI的情况下,只以异步方式命中服务。如果我以同步方式命中服务,那么我会得到我想要的结果。但是阻塞主线程是完全不能接受的。
我可以使用数组或一些全局bool变量来管理这个东西,但我不想使用它们。有没有其他方法可以让我以串行顺序获得响应?任何帮助或提示都很感激。
4条答案
按热度按时间mzillmmw1#
解决方案:使用
DispatchSemaphore
s和DispatchQueue
我没有保存闭包,而是决定将所有内容打包到一个调度队列中,并在其中使用信号量
字符串
输出始终为this
的数据
uqdfh47h2#
创意
*index 1-创建闭包时,循环中的索引
*index 2-容器中已执行操作的索引
您需要创建一个包含闭包的容器,这个容器会保存所有的闭包。容器会检查
index1 == index2
是否运行了index 1之前和if index1 + 1 > exist
之后的所有操作。因此,这个容器将检查接收到的闭包的顺序,并以升序逐个运行闭包。
详细数据
Xcode 9.4.1,Swift 4.1
容器
字符串
完整代码
不要忘记在这里添加容器的代码
型
结果
x1c 0d1x的数据
ru9i0ody3#
按顺序执行API调用的最简单方法是在前一个调用的完成处理程序中执行“下一个”调用,而不是在API调用之外使用
for
循环。字符串
我建议不要这样做,除非对顺序有一些依赖(即调用2需要调用1的结果的信息),因为它比并行请求花费更长的时间。
处理结果可能会乱序返回的事实会好得多。
此外,当使用调度组时,您需要确保在代码完成的所有情况下都调用
dispatchGroup.leave
;在您的情况下,如果发生错误,则不会这样做。这将导致dispatchGroup.notify
在一个或多个请求中发生错误时永远不会触发。3zwtqj6y4#
可以在多个地方轻松使用的代码:
字符串
使用方法:
型