Code at the end of the queue

Operation and OperationQueue are great and useful Foundation framework tools for asynchronous tasks. One thing puzzled me though: How can I run code after all my queue operations finish? The simple answer is: use dependencies between operations in the queue (unique feature of Operation). It's just 5 lines of code solution.

Operation dependency trick

with Swift it is just easy to implement as this:

extension Array where Element: Operation {
  /// Execute block after all operations from the array.
  func onFinish(_ block: @escaping () -> Void) {
    let doneOperation = BlockOperation(block: block)
    self.forEach { [unowned doneOperation] in doneOperation.addDependency($0) }
    OperationQueue().addOperation(doneOperation)
  }
}

what happened? new BlockOperation depends on all operations from the array, as such will be executed at the end, after all operations finish.

Interesting note: dependency may be set between different queues 👍

Usage

[operation1, operation2].onFinish {
    print("all done")
}

or directly with OperationQueue

operationQueue.operations.onFinish {
    print("blocks done")
}

neat!

Update: Swift 5.x introduced OperationQueue.addBarrierBlock() that may be used to schedule a closure to execute after all previously scheduled tasks. Tasks scheduled after this point will execute after barrier block finish execution.

Grand Central Dispatch trick

Of course I use GCD (import Dispatch) a lot (a way more often than Operation) because I found it convenient and fit to most of the cases. To build the same functionality I'd create DispatchGroup and use it to notify when all tasks completed, like here:

let queue = DispatchQueue(label: "my queue", attributes: .concurrent)
let group = DispatchGroup()

// called when all blocks associated with the
// dispatch group have completed.
group.notify(queue: .main) {
  print("done")
}

// dispatch asynchronous blocks
for idx in 0..<5 {
  queue.async(group: group) {
    print(idx)
  }
}

Not that neat as Operation.

Conclusion

Seriously I love 💓 this simple, small features of Swift that makes daily tasks so simple, yet powerful. If you work with Operations you may find it useful in daily hacking.

5 Apr 2020: Updated to Swift 5.2