2016-04-17 4 views
0

aufgerufen Ich muss mehrere NSOperation s zusammenfassen, die Netzwerkaufrufe in einem NSOperationQueue tun und dann warten, bis alle abgeschlossen sind.Asynchroner Rückruf in NSOperation innerhalb von NSOperationQueue wird nie

Ich füge alle NSOperation s zu meinem NSOperationQueue hinzu und rufe dann operationQueue.waitUntilAllOperationsAreFinished() an. Das funktioniert, aber es wartet unbegrenzt, da die Callbacks in NSOperations, die den Status der Operation auf 'beendet' setzen, nie aufgerufen werden.

Ich verwende die folgende NSOperation Unterklasse:

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

Dies basiert auf einem Raywenderlich Tutorial und https://gist.github.com/calebd/93fa347397cec5f88233.

Was dies tun sollten, ist die NSOperationQueue sagen, dass nur dann, wenn die main() Methode in einer Unterklasse von ConcurrentOperation den Staat .Finished setzt er abgeschlossen ist. Und das wird auch durch die Operation erfüllt.

jedoch, Wenn ich die folgende main() Methode in einer solchen ConcurrentOperation Unterklasse bauen, die NSOperationQueue hört nie auf, wie die asynchronen Teil nie genannt wird:

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

Das Problem mit einem der gleiche ist Firebase-Query Callback, den ich in meiner App verwende.

Ich versuchte, die concurrent: Bool Eigenschaft zu überschreiben und true zurückgeben, aber das repariert es auch nicht.

Wie kann ich erreichen, dass asynchrone Aufgaben tatsächlich in meiner ConcurrentOperation Unterklasse 'main() Methode ausgeführt werden?

Vielen Dank!

+0

Rufen Sie 'waitUntilAllOperationsAreFinished' in der Hauptwarteschlange auf? Wenn ja, dann hast du die Hauptwarteschlange blockiert und der 'dispatch_async (dispatch_get_main_queue() ...' Code bekommt keine Chance – Paulw11

+0

auszuführen. Ich habe das in einem 'dispatch_async (_, _) 'Block, es hat die Hauptwarteschlange blockiert. Du bist großartig! Danke! Wenn du eine normale Antwort auf meine Frage schreibst, werde ich sie als richtig markieren. @ Paulw11 – florianpfisterer

Antwort

1

Wenn Sie waitUntilAllOperationsAreFinished in der Hauptwarteschlange aufrufen, werden Sie die Hauptwarteschlange blockieren. Sobald die Hauptwarteschlange blockiert ist, kann die dispatch_async(dispatch_get_main_queue(), nicht mehr ausgeführt werden, da Sie einen Deadlock erstellt haben. Die Aufgabe, die ausgeführt werden muss, um die Hauptwarteschlange zu entsperren, wurde für die gesperrte Hauptwarteschlange ausgelöst. Daher wird sie nie ausgeführt und kann nie ausgeführt werden.

Sie müssen die waitUntilAllOperationsAreFinished in einer eigenen Warteschlange versenden.

Verwandte Themen