Quentin Malgaud
Quentin Malgaud

Reputation: 415

NSOperationQueue addOperations waitUntilFinished

Hi I am building an app using Swift. I need to process notifications in a specific order. Therefore I am trying to use addOperations waitUntilFinished.

Here is what I did:

let oldify = NSOperation()
    oldify.completionBlock = {
println("oldify")
}
let appendify = NSOperation()
    appendify.completionBlock = {
println("appendify")
}
let nettoyify = NSOperation()
    nettoyify.completionBlock = {
println("nettoyify")
}
NSOperationQueue.mainQueue().maxConcurrentOperationCount = 1
NSOperationQueue.mainQueue().addOperations([oldify, appendify, nettoyify], waitUntilFinished: true)

With this code none of the operations is being executed. When I try this instead:

NSOperationQueue.mainQueue().maxConcurrentOperationCount = 1
NSOperationQueue.mainQueue().addOperation(oldify)
NSOperationQueue.mainQueue().addOperation(appendify)
NSOperationQueue.mainQueue().addOperation(nettoyify)

The operations get executed but not in the right order.

Does anyone know what I'm doing wrong? I am getting confident in swift but completely new to NSOperations

Upvotes: 4

Views: 6148

Answers (1)

Rob
Rob

Reputation: 437552

A couple of issues:

  1. You are examining behavior of the completion block handlers. As the completionBlock documentation says:

    The exact execution context for your completion block is not guaranteed but is typically a secondary thread. Therefore, you should not use this block to do any work that requires a very specific execution context.

    The queue will manage the operations themselves, but not their completion blocks (short of making sure that the the operation finishes before its completionBlock is started). So, bottom line, do not make any assumptions about (a) when completion blocks are run, (b) the relation of one operation's completionBlock to other operations or their completionBlock blocks, etc., nor (c) which thread they are performed on.

  2. Operations are generally executed in the order in which they were added to the queue. If you add an array of operations, though, the documentation makes no formal assurances that they are enqueued in the order they appear in that array. You might, therefore, want to add the operations one at a time.

  3. Having said that, the documentation goes on to warn us:

    An operation queue executes its queued operation objects based on their priority and readiness. If all of the queued operation objects have the same priority and are ready to execute when they are put in the queue—that is, their isReady method returns YES—they are executed in the order in which they were submitted to the queue. However, you should never rely on queue semantics to ensure a specific execution order of operation objects. Changes in the readiness of an operation can change the resulting execution order. If you need operations to execute in a specific order, use operation-level dependencies as defined by the NSOperation class.

    To establish explicit dependencies, you might do something like:

    let oldify = NSBlockOperation() {
        NSLog("oldify")
    }
    oldify.completionBlock = {
        NSLog("oldify completion")
    }
    
    let appendify = NSBlockOperation() {
        NSLog("appendify")
    }
    appendify.completionBlock = {
        NSLog("appendify completion")
    }
    
    appendify.addDependency(oldify)
    
    let nettoyify = NSBlockOperation() {
        NSLog("nettoyify")
    }
    nettoyify.completionBlock = {
        NSLog("nettoyify completion")
    }
    
    nettoyify.addDependency(appendify)
    
    let queue = NSOperationQueue()
    queue.addOperations([oldify, appendify, nettoyify], waitUntilFinished: false)
    
  4. BTW, as you'll see above, you should not add operations to the main queue in conjunction with the waitUntilFinished. Feel free to add them to a different queue, but don't dispatch from a serial queue, back to itself, with the waitUntilFinished option.

Upvotes: 6

Related Questions