A Simple BlockOperation Example
Concurrency is a very interesting topic and there are many situations where you should use it in iOS development. Sometimes it is the only way to provide a responsive UI to the user. In Swift there is no language feature for concurrency yet. However, the iOS SDK provides you different concurrency APIs. In this post we’ll look at a simple example using BlockOperation.
Hint: This post has been updated to Swift 3, Xcode 8 and iOS 10
The Scenario
We want to calculate the sum of the numbers 1 to 1,000,000,000. Of course we could calculate it easily this way:
var result = (1000000000+1)*(1000000000/2)
However, sometimes you are not as smart as you could be – at least in my own experience… So we take a different approach: We want to iterate through all numbers and add them up. Unfortunately, this takes some time, so that the UI would be blocked by choosing this approach. Hence, the only way to provide a responsive UI is by calculating it concurrently. During the calculation, we want to display an activity indicator so that the user knows that something happening. After the calculation, the result should be displayed in a label and the activity indicator should stop.
Using BlockOperation
As said before, there are different concurrency APIs: You could use Grand Central Dispatch, which is great. You could also use Thread, but this is not very advisable because it is very low level. Another option is to use Operation, and there are also different ways to use it. In this post we’ll use BlockOperation. With BlockOperation you can define a block of code that should be executed on a OperationQueue of your choice.
So let’s start by creating a BlockOperation that adds up our numbers:
let blockOperation = BlockOperation { var result = 0 for i in 1...1000000000 { result += i } }
The initialiser just takes the block that should be executed. In order to run this block operation, we first need to create a OperationQueue:
let queue = OperationQueue()
All operations on this queue will not be performed on the main thread, so that the UI will not be blocked during the calculation. We can easily add our operation to the queue:
queue.addOperation(blockOperation)
Now we almost have everything we need. Except one thing: After the calculation we want do display the result. We have to do this inside the block operation because we don’t know how long the task will take. However, one thing is very important: You must not change the UI offside the main thread! UIKit is not thread safe, so that some weird problems will arise if you do that. The app can even crash.
So we need to define another block and let it be executed on the main queue:
OperationQueue.main.addOperation { self.activityIndicator.stopAnimating() self.label.text = "\(result)" self.label.isHidden = false }
Altogether, the view controller looks as follows:
import UIKit class ViewController: UIViewController { @IBOutlet weak var label: UILabel! @IBOutlet weak var activityIndicator: UIActivityIndicatorView! override func viewDidLoad() { super.viewDidLoad() activityIndicator.startAnimating() calculate() } private func calculate() { let queue = OperationQueue() let blockOperation = BlockOperation { var result = 0 for i in 1...1000000000 { result += i } OperationQueue.main.addOperation { self.activityIndicator.stopAnimating() self.label.text = "\(result)" self.label.isHidden = false } } queue.addOperation(blockOperation) } }
And – by the way – the result is 500000000500000000.
References
Title Image: @ Efired / shutterstock.com
Class Reference