Swift - Force Synchronous Execution of Work and Su

2019-03-05 11:27发布

问题:

I have a piece of code that follows the workflow:

for index in 0..<self!.recordedData.count {
//Do work here that involves fetching data from coredata and prerendering an image for each index
}
reloadUIWithData()

The workflow is intended to be:

  1. All work in the for loop to be completed

  2. ReloadUIWithData to be executed.

However, the reloadUIWithData function is being called before the work in the loop is finished. Is there any way to enforce that all work is completely finished inside the for loop, and then executing reloadUIWithData afterwards?

I have tried the following DispatchQueue Extension:

static func background(delay: Double = 0.0, background: (()->Void)? = nil, completion: (() -> Void)? = nil) {

    DispatchQueue.global(qos: .background).sync {
        background?()
        if let completion = completion {
            DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: {
                completion()
            })
        }
    }
}

By means of:

DispatchQueue.background(delay: 0.01, background: {
for index in 0..<self!.recordedData.count {
    //Do work here that involves fetching data from coredata and rendering an image for each index
    }
}, completion:{
reloadUIWithData()
}

But this doesn't seem to work in a scalable manner. While it works if the delay parameter is set to something like 0.5, setting the delay parameter to a small value such as 0.01 causes the same issue to happen. I'd like to use a more robust method than setting a random delay and hope that all work gets done within that time span.

Any help would be greatly appreciated. Thanks!

回答1:

There is a dedicated API DispatchGroup to do that. However it doesn't make the asynchronous tasks synchronous. It's like a counter which increments on enter, decrements on leave and notifies on notify when all tasks in the loop are completed (counter == 0).

let group = DispatchGroup()
for index in 0..<self!.recordedData.count {
    group.enter()
    doAsynchronousStuff { result in
        // do something with result
        group.leave()
    }
}
group.notify(queue: DispatchQueue.main) {
    self.reloadUIWithData()
}