以下是否会产生可能的竞争条件?
let syncGroup = DispatchGroup()
var tempData: [Int]
for index in 1...10 {
syncGroup.enter()
// Alamofire is being called in the following.
// I am leaving out implementation, just to simplify.
asyncTaskUsingAlamofire(completionHandler: { (data: [Data]) in
// Possible race condition?
// Should I use something like `sync()` and how?
tempData.append(data)
syncGroup.leave()
})
}
syncGroup.notify(queue: .main) {
// We can go on, all data is added to tempData
}
我可以看到swift有一个sync()
如果你怎么解决这个问题?
答案 0 :(得分:3)
与Sulthan's answer非常相似,我通常会在此方案中使用custom serial queue
let group = DispatchGroup()
var results = [Int]()
let serialQueue = DispatchQueue(label: "serialQueue")
for _ in 1...10 {
group.enter()
asyncTaskUsingAlamofire { data in
serialQueue.async {
// Multiple instances of this block will be executed into a serial queue
// So max 1 block at a time
// This means results is accessed safely
results.append(contentsOf: data)
group.leave()
}
}
}
group.notify(queue: .main) {
print(results)
}
results
数组是安全访问的,因为每个变异块的实例都是
results.append(contentsOf: data)
group.leave()
在串行队列中执行。
serialQueue.async {
results.append(contentsOf: data)
group.leave()
}
换句话说,阻止的10个实例已排入serialQueue
并一次执行 。
这确保了results
的安全访问。
答案 1 :(得分:1)
您应确保在同一队列中调用所有完成处理程序。如果未在同一队列中调用它们,则可以同时调用它们,从而创建竞争条件。
如果您不确定是否在特定队列上调用了完成处理程序,则只需插入.async
包装器:
asyncTaskUsingAlamofire(completionHandler: { (data: [Data]) in
DispatchQueue.main.async {
tempData.append(data)
syncGroup.leave()
}
}
但是,Alamofire总是在main
队列上执行回调,因此不会出现竞争条件且您的解决方案是安全的。