Online Book Reader

Home Category

Learn Objective-C on the Mac - Mark Dalrymple [154]

By Root 942 0
SlowWorker


To see how operation queues work, let’s put them to the test in SlowWorker. Before we start, make a copy of the entire folder containing your SlowWorker project. Later on in this chapter, we’re going to use the original version of SlowWorker as a starting point for another way to implement concurrency, so keep a copy of it lying around.

As you will recall, the problem with this app is that the single action method calls several other methods in sequence, the total length of which is enough to make the app feel unresponsive. What we’re going to do is put each of those other methods into an operation, put all the operations into a queue, and let the queue do its thing.

In order for this to work, one of the things we have to do is find a way for each operation to get its input from somewhere, and store its return value somewhere. The solution we’re going to use here is to make what were previously return values into instance variables in our controller class. Each method will read any input it needs from an instance variable, and put its results into another. Start by adding instance variables and properties for each of the work-methods’ return values, along with a new isWorking attribute of type BOOL, which we’ll use to keep track of whether the background operations are underway. Because the work-processing is being handled in a different way, we also need to make startTime into an instance variable. Add the lines shown in bold below to SlowWorkerAppDelegate.h:

Now, in SlowWorkerAppDelegate.m, inside the @implementation section, add@synthesize declarations for the new properties, and replace the old work-methods with the new ones shown below. We’re also going to add a new work-method called finishWorking, which takes care of updating the GUI when the work is done.

Now it’s time to update the doWork: method itself. Instead of simply executing each method directly, it creates an NSOperation for each. Then it defines a set of dependencies between these operations, so that processData is only called after fetchSomethingFromServer is done, and the two calculate methods are only called after processData is done. Here’s what it looks like:

Before going on, we’d like to explain the creation of those operations, and offer a way to improve on it. Each operation we create is actually an instance of NSInvocationOperation, which is a subclass of NSOperation. For each of those, we’re calling the lengthy initWithTarget:selector:object: method. This method takes as parameters an object to which a message should be sent, a selector specifying the method to call, and an object to pass along to the called method.

NOTE: In Objective-C, a selector is a built-in type (actually called SEL) that lets you deal with Objective-C methods and their names right in your code. In this example, we’re using it to specify in code a method name which, at run time, will be used to find the method’s actual implementation. The use of selectors, and the run-time method lookup paradigm of which they are a part, enables a lot of interesting architectural patterns in Objective-C that most other compiled languages have a hard time matching. For now, you can just think of a selector as a way to pass a method name as an argument, or assign a method name to a variable.

The problem with this setup is that each operation we create requires quite a big chunk of code, which in our case is also extremely repetitive. We’ve got the same target for all of them (self) and the same nil parameter, not to mention the huge NSInvocationOperation class name itself!

Extending NSObject


Fortunately, we can wrap this operation-creation functionality inside a method of our own, leaving a much more concise calling syntax. The new method call will be sent to the target object itself, and won’t mention NSInvocationOperation or the nil object parameter at all. What’s more, we can use an Objective-C category to add this method to NSObject, so that we can, if we want, using this new method to create operations for any object, not just our controller!

Return Main Page Previous Page Next Page

®Online Book Reader