Executing On Background Thread
Updating On Main
Coding For Responsive UI
I’ve written before about iOS networking and how network requests can throw a wildcard into application performance. The nature of the problem can vary, from response time to the amount information a request returns.
One way you can mitigate issues is by performing these requests on background threads and dispatching the UI updates that result from them back to the main thread.
Blocking vs Non-blocking
When a thread executes synchronously, that means it waits for each operation on the thread to complete before running the next one. Everything else on that thread is blocked until the current operation finishes. When an operation holds up everything else on the thread, this is called blocking.
When a thread executes asynchronously, elements begin running one after the other without waiting for the previous operation to complete. While the start times for the operations are most likely separated in time by fractions of a second, this gives the impressions that the operations all begin executing at the same time. While these processes start running at nearly the same time, their executions times can vary and end when the process comes to a conclusion.
To help manage threading, Apple provides developers with the Dispatch framework.
Dispatch comprises language features, runtime libraries, and system enhancements that provide systemic, comprehensive improvements to the support for concurrent code execution on multicore hardware in macOS, iOS, watchOS, and tvOS.
DispatchQueue manages the execution of work items. Each work item submitted to a queue is processed on a pool of threads managed by the system.
In practical terms what this means is it allows developers to decide which thread their code will execute on. Multithreading is a complicated topic, and for this post, it is not important to get into detail.
Let’s get started!
The main thread
In iOS the main thread executes synchronously. Why is this important? Synchronous queue means that operations run one after the other in order. For development purposes what that means is that if something is running synchronously, it waits for each operation to finish before moving on to the next one.
UIApplication and the Main Thread
One other thing I should mention, UIApplication runs on the applications main thread. So, if there is an operation blocking your main thread takes a long time to complete, it could wreak serious havoc with your application.
An app’s main run loop processes all user-related events. The
UIApplicationobject sets up the main run loop at launch time and uses it to process events and handle updates to view-based interfaces. As the name suggests, the main run loop executes on the app’s main thread.
For the most part, you should only use the main thread for processes that you know will finish in a short period, like UI updates. Running a long and complicated operation on the main thread will destroy your Application’s responsiveness.
To start, let’s create a ImageDownloadProtocol to define the download behavior that our class should implement:
Any class that conforms to the ImageDownloadProtocol must have an implementation of the downloadImage(from url: URL, completion: @escaping (UIImage?) -> Void) method.
Extending Our Protocol With Default Implementation
One thing we could do to simplify our code is to add a default implementation for our method in a protocol extension. That will allow any class that conforms to that protocol to use a default download image implementation.
Let’s extend ImageDownloadProtocol to give a default implementation for the method:
ViewController Conform To Protocol
Finally we can make our ViewController conform to our ImageDowloadProtocol:
Since our completion is dispatched to the main the, the code within the closure is executed on the main thread. You can check to make sure of this with the following: Thread.isMainThread.