Reputation: 1265
I need to chain together several NSOperation
s that do network calls in one NSOperationQueue
and then wait for all to be completed.
I'm adding all of the NSOperation
s to my NSOperationQueue
and then call operationQueue.waitUntilAllOperationsAreFinished()
. This works, but it waits indefinitely, as the callbacks in the NSOperations
, that set the operation's state to 'finished', get never called.
I'm using the following NSOperation
subclass:
class ConcurrentOperation: NSOperation
{
enum State: String
{
case Ready, Executing, Finished
private var keyPath: String
{
return "is" + self.rawValue
}
}
var state: State = State.Ready {
willSet (newValue)
{
self.willChangeValueForKey(newValue.keyPath)
self.willChangeValueForKey(self.state.keyPath)
}
didSet
{
self.didChangeValueForKey(oldValue.keyPath)
self.didChangeValueForKey(self.state.keyPath)
}
}
}
extension ConcurrentOperation
{
override var ready: Bool {
return super.ready && self.state == .Ready
}
override var executing: Bool {
return self.state == .Executing
}
override var finished: Bool {
return self.state == .Finished
}
override var concurrent: Bool {
return true
}
override var asynchronous: Bool {
return true
}
}
extension ConcurrentOperation
{
override func start()
{
if self.cancelled
{
self.state = .Finished
return
}
self.state = .Executing
self.main()
}
override func cancel()
{
self.state = .Finished
}
}
This is based on a Raywenderlich Tutorial and https://gist.github.com/calebd/93fa347397cec5f88233 .
What this should do is tell the NSOperationQueue that only when the main()
method in a subclass of ConcurrentOperation
sets the state to .Finished
it is completed. And this is also fulfilled by the operation.
However, If I construct the following main()
method in such a ConcurrentOperation
subclass, the NSOperationQueue
never stops as the asynchronous part is never called:
override func main()
{
dispatch_async(dispatch_get_main_queue(), {
sleep(1)
self.state = .Finished // never called!
})
}
The problem is the same with a Firebase-Query Callback that I use in my app.
I tried to override the concurrent: Bool
property and return true
, but that doesn't fix it neither.
How can I accomplish that asynchronous tasks are actually executed in my ConcurrentOperation
subclass' main()
method?
Thank you!
Upvotes: 0
Views: 1172
Reputation: 114975
If you call waitUntilAllOperationsAreFinished
on the main queue then you will block the main queue. Once the main queue is blocked the dispatch_async(dispatch_get_main_queue(),
won't be able to execute as you have created a deadlock; The task that needs to execute to unblock the main queue has been dispatched on the blocked main queue, so it will never run and can never run.
You need to dispatch the waitUntilAllOperationsAreFinished
on its own queue.
Upvotes: 1