Online Book Reader

Home Category

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

By Root 896 0
called blocks (also known as closures in some other languages), which are really important for getting the most out of GCD. The idea behind a block is to let a particular chunk of code be treated like any other C-language type. A block can be assigned to a variable, passed as an argument to a function or method, and (unlike other most other types) executed. In this way, blocks can be used as an alternative to the delegate pattern in Objective-C, or to callback functions in C. Much like a method or function, a block can take one or more parameters, and specify a return value. In order to declare a block variable, you make use of the caret (^) symbol along with some additional parenthesized bits to declare parameters and return types. To define the block itself, you do roughly the same, but follow it up with the actual code defining the block wrapped in curly-braces.

If you’ve done much C programming, you may recognize that this is similar to the concept of a function pointer in C. However, there are a few critical differences. Perhaps the biggest difference, the one that’s the most striking when you first see it, is that blocks can be defined inline in your code. You can define a block right at the point where it’s going to be passed to another method or function. Another big difference is that a block can access variables available in the scope where it’s created. By default, the block makes a copy of any variables you access this way, leaving the originals intact, but you can make an outside variable “read/write” by prepending __block before its declaration.

As we mentioned a little while ago, blocks really shine when used with GCD. GCD includes a set of functions that accomplish the same sorts of things that NSOperation and NSOperationQueue do, but with a different spin. The main difference is that, instead of explicitly creating a bunch of operations, optionally declaring inter-operation dependencies, and then assigning adding the operations to queues, with GCD you call a function that takes a block and adds it to a queue in a single step; interoperation dependencies don’t need to be declared, because the code in the block executes sequentially.

Improving SlowWorker a Second Time


To see how this works, let’s take a look at the original form of SlowWorker’s doWork: method. To get to it, open up the copy of the original SlowWorker project directory you made earlier, and use that for the rest of the changes we’re going to show.

We can make that method run entirely in the background by wrapping all the code in a block, and passing it to a GCD function called dispatch_async. This function takes two parameters: a GCD dispatch queue (conceptually similar to an NSOperationQueue) and a block to assign to the queue. Take a look:

The first line grabs a pre-existing global queue that’s always available, using the dispatch_get_global_queue() function (Unlike NSOperationQueue, with GCD there’s always a global queue available, ready to dispatch work to the background threads). That function takes two arguments: the first lets you specify a priority, and the second is currently unused and should always be 0. If you specify a different priority in the first argument, such as DISPATCH_QUEUE_PRIORITY_HIGH or DISPATCH_QUEUE_PRIORITY_LOW

(passing a 0 is the same as passing DISPATCH_QUEUE_PRIORITY_DEFAULT), you will actually get a different global queue, which the system will prioritize differently. For now, we’ll stick with the default global queue.

The queue is then passed to the dispatch_async() function, along with the block of code that comes after. GCD then takes that entire block, and passes it off to a background thread, where it will be executed one step at a time, just like it when it was running in the main thread.

Don’t Forget That Main Thread


There’s one problem here: AppKit thread safety. Remember, messaging any GUI object including our resultsTextView from a background thread is a no-no. Fortunately, GCD provides us with a way to deal with this, too. Inside the block, we can call another

Return Main Page Previous Page Next Page

®Online Book Reader