The answer is two-fold. First, we used
contentsOf to download data from the internet, which is what's known as a blocking call. That is, it blocks execution of any further code in the method until it has connected to the server and fully downloaded all the data.
Second, behind the scenes your app actually executes multiple sets of instructions at the same time, which allows it to take advantage of having two CPU cores, or even three as in the iPad Air 2. Each CPU can be doing something independently of the others, which hugely boosts your performance. These code execution processes are called threads, and come with a number of important provisos:
viewDidLoad()each. This means by default your own code executes on only one CPU, because you haven't created threads for other CPUs to work on.
Points 1 and 2 explain why our call is bad: if all user interface code must run on the main thread, and we just blocked the main thread by using
contentsOf, it causes the entire program to freeze – the user can touch the screen all they want, but nothing will happen. When the data finally downloads (or just fails), the program will unfreeze. This is a terrible experience, particularly when you consider that iPhones are frequently on poor-quality data connections.
Broadly speaking, if you're accessing any remote resource, you should be doing it on a background thread – i.e., any thread that is not the main thread. If you're executing any slow code, you should be doing it on a background thread. If you're executing any code that can be run in parallel – e.g. adding a filter to 100 photos – you should be doing it on multiple background threads.
The power of GCD is that it takes away a lot of the hassle of creating and working with multiple threads, known as multithreading. You don't have to worry about creating and destroying threads, and you don't have to worry about ensuring you have created the optimal number of threads for the current device. GCD automatically creates threads for you, and executes your code on them in the most efficient way it can.
To fix our project, you need to learn three new GCD functions, but the most important one is called
async() – it means "run the following code asynchronously," i.e. don't block (stop what I'm doing right now) while it's executing. Yes, that seems simple, but there's a sting in the tail: you need to use closures. Remember those? They are your best friend. No, really.
Build for watchOS
Take your existing Swift skills to Apple's tiniest platform – check out Hacking with watchOS!