Advanced NSOperations

Description: Operations are a flexible way to model your app's business logic, but they can do so much more. See how NSOperation forms the heart of the WWDC app, and how using features like dependencies, readiness, and composition allow you to quickly and easily build dynamic and complex apps.

Core concepts

  • NSOperationQueue
    • Wrapper around dispatch queue
    • Makes it easy to cancel operations that have not began executing
    • Lets us specify the max number of concurrent operations, can be changed later (if max == 1, this becomes a serial queue)
  • NSOperation
    • Wrapper around a dispatch block
    • can run several minutes (dispatch blocks too, but it’s not the expected behavior for those)
    • subclassable

NSOperation Lifecycle

  • Once created the operation starts in a pending state
  • After putting it in its queue, the state will move to ready to execute
  • Then the operation queue at some point will fetch the operation and begin executing it.
  • After the execution finishes, the state will move to finished
  • At any point, the operation state can also move to cancelled (unless it has finished already)

NSOperation Cancellation

  • defined as a boolean (cancelled) in the NSOperation object.
  • When we cancel an operation, what the system does is set this boolean
  • Up to us (or our subclass) to decide what does it mean for the operation to be cancelled
  • Up to us to observe changes in this boolean value and react on it
  • Note that there might be scenarios when the cancellation event comes too late and the operation finished before the event reaches the object

NSOperation Ready state

  • Again, defined as a boolean (ready).
  • Reflects that the operation is ready to execute

NSOperation dependencies

  • Strict ordering
  • By default an operation becomes ready only when all its dependencies have been executed
  • Not limited by operation queues: an operation can depend on operations in different operation queues
  • Be aware of deadlocks! (No mutual dependencies)

Beyond the basics

  • If an operation has dependencies, let that operation create by itself those operations: this way we don’t need to create every time multiple levels of dependencies by ourselves, but strictly the dependencies needed by us, and they will take care of everything else. This is super powerful especially for reusability
  • It’s ok to add UI things inside the operations
  • It’s ok to have dispatch blocks inside the operations
  • Add requirements:
    • user location
    • User logged in
    • Internet availability
  • These requirements can be reflected by the ready state
  • Composing Operations
    • We can also create operations that internally have other operations,
    • e.g. an object request can be composed by a file download and a file parse
    • e.g. fetch all favorites the internal operation is a loop of fetches that continue until we fetch all the favorites (in case they’re paginated)
  • Mutual exclusivity

Missing anything? Corrections? Contributions are welcome 😃

Written by

Federico Zanetello

Federico Zanetello

Software engineer with a strong passion for well-written code, thought-out composable architectures, automation, tests, and more.