Swift 组合信号量以限制异步请求和调度组。notify with defer和App处于冻结状态

Swift 组合信号量以限制异步请求和调度组。notify with defer和App处于冻结状态,swift,asynchronous,grand-central-dispatch,Swift,Asynchronous,Grand Central Dispatch,我有一个后端,可以同时处理最多4个网络连接。为了补偿,我制作了一个名为urlsquee的数组,其中包含每个网络请求所需的所有参数。如果urlsQueue包含4个或更少的元素,下面的代码将生成我想要的结果。但是,如果我输入func downloadBusiness,并在urlsquee中包含5个以上元素,则应用程序将冻结 func downloadBusinesses(latitude: Double, longitude: Double){ if urlsQueue.isEmpty {r

我有一个后端,可以同时处理最多4个网络连接。为了补偿,我制作了一个名为
urlsquee
的数组,其中包含每个网络请求所需的所有参数。如果
urlsQueue
包含4个或更少的元素,下面的代码将生成我想要的结果。但是,如果我输入
func downloadBusiness
,并在
urlsquee
中包含5个以上元素,则应用程序将冻结

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()
    }
}
如果网络请求成功,我将从
urlsquee
中删除相应的值。如果网络请求失败,条目将保留在
urlsquee
中。在遍历
urlsquee
中的每个元素之后,如果循环不是空的,我将再次重复该过程。这样我就可以重新执行任何失败的网络请求

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枚举循环中。在循环的第四次之后,一切都停止了。如果我正在逐步完成这个计划,我就无法前进。如果我将硬编码值4调整为任何其他整数,则问题会重复,只有在
urlsQueue.count
时代码块才会成功,因为您总是从URL队列的索引0开始,如果索引>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()
    }
}

由于总是从URL队列的索引0开始,如果索引>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()
    }
}
在您评论“GCD闭包不会导致保留周期”时,它不会创建一个周期,因为您没有保留DispatchGroup,并且闭包在处理后会被释放。如果您没有正确调用
leave
,则它将被保留。在您的评论中说“GCD闭包不会导致保留周期”,它不会创建周期,因为您没有保留DispatchGroup,并且闭包在处理后会被释放。如果您没有正确调用
离开
,它将被保留。