Asynchronous Callback in NSOperation inside of NSOperationQueue is never called

荒凉一梦 提交于 2020-01-06 19:30:47

问题


I need to chain together several NSOperations that do network calls in one NSOperationQueue and then wait for all to be completed.

I'm adding all of the NSOperations 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!


回答1:


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.



来源:https://stackoverflow.com/questions/36675986/asynchronous-callback-in-nsoperation-inside-of-nsoperationqueue-is-never-called

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