问题
I know there are a lot of contributions already for this topic. I tried different variations with DispatchGroup, but it seems I'm not able to make the whole loop stop until a certain task is finished.
let names = ["peter", "susan", "john", "peter", "susan", "john"]
var holding = [String: [Double]]()
for i in 0...10 {
for name in names {
if holding[name] == nil {
Alamofire.request("https://jsonplaceholder.typicode.com", parameters: parameters).responseJSON { responseData in
// do stuff here
holding[name] = result
}
} else {
// do other stuff with existing "holding[name]"
}
// if if holding[name] == nil, the whole process should wait
}
}
If I´m using DispatchGroup, the Alamofire requests are executed one by one, but the the whole loop doesn't recognize if holding[name]
does already exist. So holding[name]
is always nil
because the loop doesn't wait.
Thank you very much!
EDIT:
According to Mikes´s and Versus´ answers, I tried the following:
var names = ["peter", "susan", "john", "peter", "susan", "john"]
var holding = [String: [Double]]()
let semaphore = DispatchSemaphore(value: 1)
for i in 0...10 {
DispatchQueue.global().async { [unowned self] in
self.semaphore.wait()
for name in names {
if holding[name] != nil {
Alamofire.request("https://jsonplaceholder.typicode.com", parameters: parameters).responseJSON { responseData in
// do stuff here
holding[name] = result
semaphore.signal()
}
} else {
// do other stuff with existing "holding[name]"
semaphore.signal()
}
// if if holding[name] != nil, the wholeprocess should wait
}
}
}
But unfortunately the app crashes. What am I doing wrong?
回答1:
You have two choice here
1 ) Semaphore
2 ) Operation Queues
But you should think twice before you go with Semaphores
you need to be cautious about semaphore.signal()
and semaphore.wait()
pair
As Semaphore
may block Main Thread so all operation should be done in Dispatch.global.async
i.e
semaphore.wait()
Alamofire.request("https://jsonplaceholder.typicode.com", parameters: parameters).responseJSON { responseData in
semaphore.signal()
holding[name] = result
}
Here you are block the main thread
The problem is that the completion handler gets executed in the main thread, which was already locked by the semaphore.wait() called initially. So when the completion occurs, semaphore.signal() never gets called
You must go with
DispatchQueue.global().async { [unowned self] in
self.semaphore.wait()
// And other statemetns
}
Hope it is helpful to you and other
回答2:
I think you can use DispatchSemaphore to stop the loop:
let semaphore = DispatchSemaphore(value: 1)
for i in 0...10 {
for name in names {
// if signal is 0, loop will be stopped forever,
// if signal > 0, loop will continue
semaphore.wait()
if holding[name] == nil {
Alamofire.request("https://jsonplaceholder.typicode.com", parameters: parameters).responseJSON { responseData in
// do stuff here
// release signal to continue current loop(signal + 1)
semaphore.signal()
holding[name] = result
}
} else {
// do other stuff with existing "holding[name]"
}
// if if holding[name] == nil, the whole process should wait
}
}
来源:https://stackoverflow.com/questions/46091920/how-to-make-a-loop-wait-until-task-is-finished