Chapters

Hide chapters

Concurrency by Tutorials

Second Edition · iOS 13 · Swift 5.1 · Xcode 11

Before You Begin

Section 0: 3 chapters
Show chapters Hide chapters

10. Canceling Operations
Written by Scott Grosch

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

With an operation, you have the capability of canceling a running operation as long as it’s written properly. This is very useful for long operations that can become irrelevant over time. For instance, the user might leave the screen or scroll away from a cell in a table view. There’s no sense in continuing to load data or make complex calculations if the user isn’t going to see the result.

The magic of cancel

Once you schedule an operation into an operation queue, you no longer have any control over it. The queue will schedule and manage the operation from then on. The one and only change you can make, once it’s been added to the queue, is to call the cancel method of Operation.

There’s nothing magical about how canceling an operation works. If you send a request to an operation to stop running, then the isCancelled computed property will return true. Nothing else happens automatically! At first, it may seem strange that iOS doesn’t stop the operation automatically, but it’s really not.

What does canceling an operation mean to the OS?

  • Should the operation simply throw an exception?
  • Is there cleanup that needs to take place?
  • Can a running network call be canceled?
  • Is there a message to send server-side to let something else know the task stopped?
  • If the operation stops, will data be corrupted?

With just the small list of issues presented in the bullets above, you can see why setting a flag identifying that cancellation has been requested is all that’s possible automatically.

The default start implementation of Operation will first check to see whether the isCancelled flag is true, and exit immediately if it is.

Cancel and cancelAllOperations

The interface to cancel an operation is quite simple. If you just want to cancel a specific Operation, then you can call the cancel method. If, on the other hand, you wish to cancel all operations that are in an operation queue, then you should call the cancelAllOperations method defined on OperationQueue.

Updating AsyncOperation

In this chapter, you’ll update the app you’ve been working on so that a cell’s operations are canceled when the user scrolls away from that cell.

override func start() {
  main()
  state = .executing
}
override func start() {
  if isCancelled {
    state = .finished
    return
  }
  
  main()
  state = .executing
}

Canceling a running operation

To support the cancellation of a running operation, you’ll need to sprinkle checks for isCancelled throughout the operation’s code. Obviously, more complex operations are going to be able to check in more places than something simple like your NetworkImageOperation.

guard !self.isCancelled else { return }
private var task: URLSessionDataTask?
task = URLSession.shared.dataTask(with: url) { [weak self]
task?.resume()
override func cancel() {
  super.cancel()
  task?.cancel()
}
guard !isCancelled else { return }
guard !isCancelled else { return }
private var operations: [IndexPath: [Operation]] = [:]
if let existingOperations = operations[indexPath] {
  for operation in existingOperations {
    operation.cancel()
  }
}

operations[indexPath] = [tiltShiftOp, downloadOp]
override func tableView(
  _ tableView: UITableView, 
  didEndDisplaying cell: UITableViewCell, 
  forRowAt indexPath: IndexPath) {
  
  if let operations = operations[indexPath] {
    for operation in operations {
      operation.cancel()
    }
  }
}

Where to go from here?

Having to cancel an operation doesn’t necessarily mean something negative happened. At times you cancel an operation because it’s simply no longer necessary. If you’re working with a UITableView or a UICollectionView you may want to implement the prefetching delegate methods introduced in iOS 10. When the controller is going to prefetch, you’d create the operations. If the controller cancels prefetching, you’d cancel the operations as well.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now