Learn Objective-C on the Mac - Mark Dalrymple [151]
Chapter16
Concurrency
One of the biggest challenges in software development is writing software that will do more than one thing at a time. For decades, computers have been able to give an illusion of concurrency by quickly switching between tasks at a high rate, making it seem that they’re doing several things at once (when in reality, they’re continuously flipping from one task to the next, only “paying attention” to one at a time). Today’s computers frequently contain two or more computation cores, so that they really can do multiple things at once, simultaneously executing instructions on all cores at the same time.
However, even if your computer’s hardware and OS are capable of working with a multitude of cores, writing application software that can effectively make use of multiple cores is still technically challenging. In most development environments, the default assumption is that the code you’re writing is performed sequentially, one operation after the other, and splitting things up so that work can be performed concurrently can be a pretty big task.
In this chapter, we’ll present an example of a common situation in which Cocoa applications can benefit from concurrency, and show you how it’s done. You’re surely familiar with Mac OS X’s spinning disk cursor (sometimes called the “spinning beachball of death”) which appears whenever an application isn’t responding to user actions. This typically appears after you click a button or menu item that triggers any sort of processing that takes more than a few seconds. Mac OS X notices that your process isn’t handling input events, and shows the spinning disk cursor to alert the user. This also happens whenever an application has really stopped responding entirely, and is on its way to crashing (or being killed by the user). So when your app stops responding, and starts showing the spinning disk cursor, the immediate reaction for many users is a moment of panic when they suspect that your app is about to crash!
Therefore, it’s in your best interests to make sure that any sort of long-running operation in your application is handled in such a way that the user can still interact with your application and not get the spinning disk, by making the operation occur in the background, letting your application still handle user input events as it normally does. This chapter will demonstrate two ways to add this sort of concurrency to a Cocoa application with a minimum of fuss. We’ll use the concepts embodied by the NSOperation and NSOperationQueue classes available in Leopard (as well as on the iPhone), and also show you how it can be done using the new Grand Central Dispatch, available only in Snow Leopard.
SlowWorker
As a platform for demonstrating these concurrency options, we’ll create a simple application called SlowWorker, which simulates doing some long-running operations such as fetching data from a server, and performing some calculations. This app presents the user with a button to initiate some work, and shows the results in a text view when it’s done (see Figure 16-1).
Figure 16-1. The SlowWorker in action (inaction?).
Start by making a new Cocoa application (no Core Data or Document support is necessary) in Xcode, and doing the usual steps of enabling garbage collection, and creating a SlowWorkerAppDelegate class and adding it to the MainMenu.xib if necessary (say, if you’re running Leopard, and Xcode didn’t create it for you). Put the following code into