2016-04-17 2 views
0

Мне нужно связать несколько NSOperation s, которые выполняют сетевые вызовы в одном NSOperationQueue, а затем дождитесь завершения всех операций.Асинхронный обратный вызов в NSOperation внутри NSOperationQueue никогда не называется

Я добавляю все NSOperation s к моему NSOperationQueue, а затем звоните operationQueue.waitUntilAllOperationsAreFinished(). Это работает, но он ждет неопределенно долгое время, поскольку обратные вызовы в NSOperations, которые задают состояние операции «закончен», никогда не вызываются.

Я использую следующий NSOperation подкласс:

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 
    } 
} 

Это основано на Raywenderlich Tutorial и https://gist.github.com/calebd/93fa347397cec5f88233.

Что это должно сделать, это сказать NSOperationQueue, что только тогда, когда метод main() в подклассе ConcurrentOperation устанавливает государство .Finished его достройки. И это также выполняется операцией.

Однако, если я построить следующий main() метод в такой ConcurrentOperation подклассе NSOperationQueue никогда не останавливается, как асинхронная часть никогда не вызывается:

override func main() 
{ 
    dispatch_async(dispatch_get_main_queue(), { 
     sleep(1) 
     self.state = .Finished // never called! 
    }) 
} 

Проблема состоит в том же, с Firebase-Query Callback, который я использую в своем приложении.

Я попытался переопределить свойство concurrent: Bool и вернуть true, но это не исправляет его.

Как я могу выполнить, что асинхронные задачи выполняются в моем ConcurrentOperation подклассе main()?

Спасибо!

+0

Вы вызываете 'waitUntilAllOperationsAreFinished' в главной очереди? Если это так, то вы заблокировали основную очередь, а код 'dispatch_async (dispatch_get_main_queue() ...» не получает возможности выполнить – Paulw11

+0

. Даже если я делаю это в 'dispatch_async (_, _) 'block, он заблокировал основную очередь. Вы потрясающий! Спасибо! Если вы напишете правильный ответ на мой вопрос, я буду отмечать его как правильно. @ Paulw11 – florianpfisterer

ответ

1

Если вы вызываете waitUntilAllOperationsAreFinished в основной очереди, вы заблокируете основную очередь. Как только основная очередь заблокирована, dispatch_async(dispatch_get_main_queue(), не сможет выполнить, поскольку вы создали тупик; Задача, которая должна выполняться для разблокирования главной очереди, была отправлена ​​в заблокированной основной очереди, поэтому она никогда не будет работать и никогда не будет работать.

Вам необходимо отправить waitUntilAllOperationsAreFinished в свою очередь.