
Threads allows you to execute multiple code paths concurrently within your application. The reason you’ll use it is to speed up the performance of your application by running some code on another thread while other operations are happening on the main thread. This is helpful for when you need to pre-load data. I’ve used this before in a magazine app where I needed to pre-load the next couple of pages while the user is reading the current page, this made the application much smoother when swiping to the next page.
There are a couple of disadvantages to threads, one problem with creating threads yourself is that they add uncertainty to your code. Threads are a relatively low-level and complicated way to support concurrency in your application. If you do not fully understand the implications of your design choices, you could easily encounter synchronization or timing issues, the severity of which can range from subtle behavioral changes to the crashing of your application and the corruption of the user’s data. Another problem area with Cocoa and multithreading comes from user interface updates. All UI updates in Cocoa must be done on the main thread, or instability can result. If you have a background thread performing a calculation, make sure to wrap whatever method updates the UI in a -performSelectorOnMainThread:withObject:waitUntilDone: method call. The single biggest source of crashes with multithreaded Cocoa applications is simultaneous access to a shared resource.
Grand Central Dispatch (GCD)
Grand Central Dispatch is one of the most common ways to add threads. With GCD, you define the task you want to perform and add it to a work queue, which handles the scheduling of your task on an appropriate thread. Work queues take into account the number of available cores and the current load to execute your tasks more efficiently than you could do yourself using threads.
Adding a Task to a Queue
dispatch_async(myQueue, ^{ // Insert code to be executed on another thread here [self methodName]; }); dispatch_release(myQueue);
To execute a task, you must dispatch it to an appropriate dispatch queue. You can dispatch tasks synchronously or asynchronously. Once in a queue, the queue becomes responsible for executing your tasks as soon as possible, given its constraints and the existing tasks already in the queue. Do not call the dispatch_sync function from a task that is executing on the same queue that you pass to your function call. Doing so will deadlock the queue. If you need to dispatch to the current queue, do so asynchronously using the dispatch_async function.
Performing Tasks on the Main Thread
You can use to execute tasks on your application’s main thread while you’re running code on another thread. You can get the dispatch queue for your application’s main thread by calling the dispatch_get_main_queue function. Tasks added to this queue are performed serially on the main thread itself. Therefore, you can use this queue as a synchronization point for work being done in other parts of your application.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ // Insert code to be executed on another thread here [self methodName]; dispatch_async(dispatch_get_main_queue(), ^{ // Insert code to be executed on the main thread here [self methodName]; }); }); dispatch_release(queue);
Suspending and Resuming Queues
It’s not possible to stop a queue after it has been called because it would cause your application to be unstable but you can pause and resume the queue. You suspend a dispatch queue using the dispatch_suspend function and resume it using the dispatch_resume function.
-(void) startRunning { // queue will need to be defined in your header since it's use globally in the class queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ // Insert code to be executed on another thread here [self methodName]; }); } -(void) userCancels { if (queue) { dispatch_suspend(queue); } } -(void) userResumes { if (queue) { dispatch_resume(queue); } } -(void) dealloc { if (queue) dispatch_release(queue); [super dealloc[; }