我有一个后端,最多可以同时处理4个网络连接。为了补偿,我制作了一个名为urlsQueue
的数组,其中包含每个网络请求所需的所有参数。如果urlsQueue
包含4个或更少的元素,下面的代码将产生我想要的结果。但是,如果我输入func downloadBusiness
中包含5个以上元素的urlsQueue
,则该应用程序冻结。
func downloadBusinesses(latitude: Double, longitude: Double){
if urlsQueue.isEmpty {return}
let semaphore = DispatchSemaphore(value: 4)
let dispatchGroup = DispatchGroup()
for (index, element) in urlsQueue.enumerated(){
dispatchGroup.enter()
semaphore.wait()
_ = Client.getBusinesses(latitude: latitude, longitude: longitude, offset: element.offset ,completion: { [weak self] (yelpDataStruct, result) in
defer {
semaphore.signal()
dispatchGroup.leave()
}
self?.handleGetNearbyBusinesses(inputData: yelpDataStruct, result: result)
})
}
dispatchGroup.notify(queue: .main) {[weak self] in
self?.runDownloadAgain()
}
}
如果网络请求成功,我将从urlsQueue
中删除相应的值。如果网络请求失败,则该条目保留在urlsQueue
中。遍历urlsQueue
中的每个元素之后,如果循环不为空,我将再次重复该过程。这样,我可以重新执行任何失败的网络请求。
func runDownloadAgain(){
let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { [weak self] timer in
self?.downloadBusinesses(latitiude: self!.latitude, longitude: self!.longitude)
}
timer.fire()
}
我能够在上面的for-enumerated循环中调试应用程序中的断点。在循环中的第4次之后,一切都停止了。如果我正在逐步执行该程序,则无法前进。如果将硬编码的值4调整为任何其他整数,则仅当urlsQueue.count
<= x(其中x是DispatchSemaphore(value: x)
问题出在我的dispatchGroup / semaphore / defer混合不当。但是,我真的很想知道如何才能成功地重新组合这些元素,以避免在将网络连接限制为4个的同时避免应用冻结。
答案 0 :(得分:1)
当您始终从URL队列的索引零开始时,如果索引> 3并退出信号量,则会退出循环
func downloadBusinesses(latitiude: Double, longitude: Double){
if urlsQueue.isEmpty {return}
let dispatchGroup = DispatchGroup()
for (index, element) in urlsQueue.enumerated(){
if index > 3 { break }
dispatchGroup.enter()
_ = Client.getBusinesses(latitude: latitude, longitude: longitude, offset: element.offset ,completion: { [weak self] (yelpDataStruct, result) in
defer {
dispatchGroup.leave()
}
self?.handleGetNearbyBusinesses(inputData: yelpDataStruct, result: result)
})
}
dispatchGroup.notify(queue: .main) { // GCD closures don't cause retain cycles
self.runDownloadAgain()
}
}