How to make a loop wait until task is finished

旧街凉风 提交于 2019-12-24 20:22:24

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!