Operation and OperationQueue Tutorial in Swift
In this tutorial, you will create an app that uses concurrent operations to provide a responsive interface for users by using Operation and OperationQueue. By James Goodwill.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Operation and OperationQueue Tutorial in Swift
35 mins
Everyone has had the frustrating experience of tapping a button or entering some text in an iOS or Mac app, when all of a sudden: WHAM! The user interface stops responding.
On the Mac, your users get to stare at the colorful wheel rotating for a while until they can interact with the UI again. In an iOS app, users expect apps to respond immediately to their touches. Unresponsive apps feel clunky and slow, and usually receive bad reviews.
Keeping your app responsive is easier said than done. Once your app needs to perform more than a handful of tasks, things get complicated quickly. There isn’t much time to perform heavy work in the main run loop and still provide a responsive UI.
What’s a poor developer to do? The solution is to move work off the main thread via concurrency. Concurrency means that your application executes multiple streams (or threads) of operations all at the same time. This way the user interface stays responsive as you’re performing your work.
One way to perform operations concurrently in iOS is with the Operation
and OperationQueue
classes. In this tutorial, you’ll learn how to use them! You’ll start with an app that doesn’t use concurrency at all, so it will appear very sluggish and unresponsive. Then, you’ll rework the app to add concurrent operations and provide a more responsive interface to the user!
Getting Started
The overall goal of the sample project for this tutorial is to show a table view of filtered images. The images are downloaded from the Internet, have a filter applied, and then displayed in the table view.
Here’s a schematic view of the app model:
A First Try
Use the Download Materials button at the top or bottom of this tutorial to download the starter project. It is the first version of the project that you’ll be working on in this tutorial.
Build and run the project, and (eventually) you’ll see the app running with a list of photos. Try scrolling the list. Painful, isn’t it?
All of the action is taking place in ListViewController.swift, and most of that is inside tableView(_:cellForRowAtIndexPath:)
.
Have a look at that method and note there are two things taking place that are quite intensive:
- Loading the image data from the web. Even if this is easy work, the app still has to wait for the download to be complete before it can continue.
- Filtering the image using Core Image. This method applies a sepia filter to the image. If you would like to know more about Core Image filters, check out Beginning Core Image in Swift.
In addition, you’re also loading the list of photos from the web when it is first requested:
lazy var photos = NSDictionary(contentsOf:dataSourceURL)!
All of this work is taking place on the main thread of the application. Since the main thread is also responsible for user interaction, keeping it busy with loading things from the web and filtering images is killing the responsiveness of the app. You can get a quick overview of this by using Xcode’s gauges view. You can get to the gauges view by showing the Debug navigator (Command-7) and then selecting CPU while the app is running.
You can see all those spikes in Thread 1, which is the main thread of the app. For more detailed information, you can run the app in Instruments, but that’s a whole other tutorial. :]
It’s time to think about how can you improve that user experience!
Tasks, Threads and Processes
Before going further, there are a few technical concepts you need to understand. Here are some key terms:
- Task: a simple, single piece of work that needs to be done.
- Thread: a mechanism provided by the operating system that allows multiple sets of instructions to operate at the same time within a single application.
- Process: an executable chunk of code, which can be made up of multiple threads.
The Foundation framework contains a class called Thread, which is much easier to deal with, but managing multiple threads with Thread is still a headache. Operation and OperationQueue are higher level classes that have greatly simplified the process of dealing with multiple threads.
The Foundation framework contains a class called Thread, which is much easier to deal with, but managing multiple threads with Thread is still a headache. Operation and OperationQueue are higher level classes that have greatly simplified the process of dealing with multiple threads.
In this diagram, you can see the relationship between a process, threads, and tasks:
As you can see, a process can contain multiple threads of execution, and each thread can perform multiple tasks one at a time.
In this diagram, thread 2 performs the work of reading a file, while thread 1 performs user-interface related code. This is quite similar to how you should structure your code in iOS — the main thread performs any work related to the user interface, and secondary threads perform slow or long-running operations such as reading files, accessing the network, etc.