在所有异步请求完成后收到通知。
我在下面的循环中多次调用registerTrack
。我希望仅在 所有 请求完成时触发syncGroup.notify
。通过查看此代码,每次成功完成notify
后,它将转到registerTrack
。如何在所有notify
操作完成后才发出信号registerTrack
?
我的代码如下:
var fail = false
let syncGroup = DispatchGroup() //used so we can determine if all the register requests have finished
for track in unsyncedTracks {
syncGroup.enter()
if fail {
syncGroup.leave()
break //might save an aync request from getting executed on failure
}
registerTrack(track: track, withCompletion: { (success: Bool) -> () in
if success {
self.debug.log(tag: "RecordViewController", content: "Registered track: \(track.name)")
syncGroup.leave()
}
else {
fail = true
syncGroup.leave()
}
})
}
//all requests complete
syncGroup.notify(queue: .main) {
if fail {
complete(false)
}
else {
self.debug.log(tag: "RecordViewController", content: "Finished registering all unsynced tracks")
complete(true)
}
}
编辑:
根据建议使用GCD并发队列,我将代码更改为:
var failed = false
//work item to loop through and call registerTrack on each track
let registerTracksWorkItem = DispatchWorkItem {
for track in unsyncedTracks {
if failed { //exit early on failure, potentially save a network request
break
}
self.registerTrack(track: track, withCompletion: { (success: Bool) -> () in
if success {
self.debug.log(tag: "RecordViewController", content: "Registered track: \(track.name)")
}
else {
failed = true
}
})
}
}
//handler for when all registerTrack calls are complete
registerTracksWorkItem.notify(queue: DispatchQueue.main) {
if failed {
self.debug.log(tag: "RecordViewController", content: "At least one registerTrack call failed")
complete(false)
}
else {
self.debug.log(tag: "RecordViewController", content: "Finished registering all unsynced tracks")
complete(true)
}
}
//execute the work item
let queue = DispatchQueue.global()
queue.async(execute: registerTracksWorkItem)
此代码不等待registerTrack
完成,而是全部执行它们并调用notify
事件。 :(
编辑3:
所以这很有效。它使用计数器来检查它是否在最终的unsyncedTracks
对象中。
var fail = false
let syncGroup = DispatchGroup() //used so we can determine if all the register requests have finished
//used to make sure notify is only triggered when all registerTracks are complete
let unsyncedTracksCount = unsyncedTracks.count
var completeCounter = 0
syncGroup.enter()
for track in unsyncedTracks {
registerTrack(track: track, withCompletion: { (success: Bool) -> () in
if success {
self.debug.log(tag: "RecordViewController", content: "Registered track: \(track.name)")
}
else {
fail = true
}
completeCounter = completeCounter + 1
if completeCounter == unsyncedTracksCount {
syncGroup.leave()
}
})
}
//all requests complete
syncGroup.notify(queue: .main) {
if fail {
complete(false)
}
else {
self.debug.log(tag: "RecordViewController", content: "Finished registering all unsynced tracks")
complete(true)
}
}
我可以这样做吗(它似乎也有效)?我添加了if if,leave()
if。
var fail = false
let syncGroup = DispatchGroup() //used so we can determine if all the register requests have finished
//used to make sure notify is only triggered when all registerTracks are complete
let unsyncedTracksCount = unsyncedTracks.count
var completeCounter = 0
syncGroup.enter()
for track in unsyncedTracks {
if fail { //might save an aync request from getting executed on failure
syncGroup.leave()
break
}
registerTrack(track: track, withCompletion: { (success: Bool) -> () in
if success {
self.debug.log(tag: "RecordViewController", content: "Registered track: \(track.name)")
}
else {
fail = true
}
completeCounter = completeCounter + 1
if completeCounter == unsyncedTracksCount {
syncGroup.leave()
}
})
}
//all requests complete
syncGroup.notify(queue: .main) {
if fail {
complete(false)
}
else {
self.debug.log(tag: "RecordViewController", content: "Finished registering all unsynced tracks")
complete(true)
}
}
答案 0 :(得分:0)
因此,问题与您的fail
变量和for
循环结构有关。在循环执行之前将fail
指定为false
。当您编码进入循环并注册.enter()
时,它会检查if fail
条件并在.leave()
为fail
时调用true
。基本上,当其中一个registerTrack()
调用将fail
设置为true
时,您的代码处于未确定状态,因为registerTrack()
是异步的,您不知道哪个.enter()
次调用将标记设置为true
。
当.enter()
计数等于.leave()
计数(例如,两个连续失败)时,CGD决定您的队列已完成并且被称为.notify()
"过早地&#34 ;
我建议您删除标记fail
(代码将按预期工作,但会为所有registerTrack()
执行unsyncedTracks
并重新考虑您的解决方案和逻辑。例如,DispatchWorkItem.cancel()
可以解决您的问题。