6. Blocks and Grand Central Dispatch

Multithreaded programming is something that every developer is going to need to think about with modern application development. Even if you don’t think that your application is multithreaded, it most probably is because system frameworks often use extra threads to get work done off the UI thread. There’s nothing worse than an application that hangs because the UI thread is blocked. In Mac OS X, this results in the dreaded spinning beach ball; in iOS, your application may be terminated if it blocks for too long.

Fortunately, Apple has thought about multithreading in a whole new way. The core features of modern multithreading are blocks and Grand Central Dispatch (GCD). Although distinct and separate technologies, they were introduced together. Blocks provide lexical closures to C, C++, and Objective-C and are incredibly useful, mainly because they provide a mechanism to pass around code as if it were an object, to be run in a different context. Crucially, though, blocks can use anything from the scope in which they were defined.

GCD is the associated technology and provides an abstraction to threading, based on so-called dispatch queues. Blocks can be enqueued on these queues, and GCD handles all scheduling for you. It creates, reuses, and destroys background threads as it sees fit, based on system resources, to process each queue. Moreover, GCD provides easy-to-use solutions to common programming tasks, such as thread-safe single-code execution and running the tasks in parallel, based on available system resources.

Both blocks and GCD are a mainstay of modern Objective-C programming. Therefore, you need to understand how they work and what they provide.

Item 37: Understand Blocks

Blocks provide closures. This language feature was added as an extension to the GCC compiler and is available in all modern Clang versions (the compiler project used for Mac OS X and iOS development). The runtime component required for blocks to function correctly is available in all versions of Mac OS X since 10.4 and iOS since 4.0. The language feature is technically a C-level feature and therefore can be used in C, C++, Objective-C, and Objective-C++ code compiled under a supported compiler and run with the block runtime present.

Block Basics

A block is similar to a function but is defined inline to another function and shares the scope of that within which it is defined. The symbol used to denote a block is the caret, followed by a scope block that contains the block’s implementation. For example, a simple block looks like this:

Click here to view code image

^{
    // Block implementation here
}

A block is simply another value and has an associated type. Just like an int, float, or Objective-C object, a block can be assigned to a variable and then used like any other variable. The syntax for a block type is similar to that of a function pointer. Following is a simple example of a block that takes no parameters and returns nothing:

Click here to view code image

void (^someBlock)() = ^{
    // Block implementation here
};

This block defines a variable whose name is someBlock. This might look strange because the variable name is right in the middle, but once you understand the syntax, it is easy to read. The structure of the block type syntax is as follows:

return_type (^block_name)(parameters)

To define a block that returns an int and takes two ints as parameters, you would use the following syntax:

Click here to view code image

int (^addBlock)(int a, int b) = ^(int a, int b){
    return a + b;
};

A block can then be used as if it were a function. So, for example, the addBlock could be used like this:

int add = addBlock(2, 5); //< add = 7

The powerful feature that blocks allow is capturing the scope in which they are declared. This means that any variables available to the scope in which the block is declared are also available inside the block. For example, you could define a block that used another variable like this:

Click here to view code image

int additional = 5;
int (^addBlock)(int a, int b) = ^(int a, int b){
    return a + b + additional;
};
int add = addBlock(2, 5); //< add = 12

By default, any variable captured by a block cannot be modified by the block. In the example, if the variable called additional were changed within the block, the compiler would issue an error. However, variables can be declared as modifiable by giving them the __block qualifier. For example, a block can be used in array enumeration (see Item 48) to determine how many numbers in an array are less than 2:

Click here to view code image

NSArray *array = @[@0, @1, @2, @3, @4, @5];
__block NSInteger count = 0;
[array enumerateObjectsUsingBlock:
    ^(NSNumber *number, NSUInteger idx, BOOL *stop){
        if ([number compare:@2] == NSOrderedAscending) {
            count++;
        }
    }];
// count = 2

This example also shows the use of an inline block. The block passed to the enumerateObjectsUsingBlock: method is not assigned to a local variable but rather declared inline to the method call. This commonly used coding pattern with blocks shows why they are so useful. Before blocks became part of the language, the preceding code would have to be done by passing a function pointer or selector name that the enumeration method could call. State would have to be passed in and out manually, usually through an opaque void pointer, thereby introducing additional code and splitting up the method somewhat. Declaring a block inline means that the business logic is all in one place.

When it captures a variable of object type, a block implicitly retains it. It will be released when the block itself is released. This leads to a point about blocks that is important to understand. A block itself can be considered an object. In fact, blocks respond to many of the selectors that other Objective-C objects do. Most important to understand is that a block is reference counted just like other objects. When the last reference to a block is removed, it is deallocated. In doing so, any objects that the block captures are released to balance out the block’s retain of them.

If the block is defined in an instance method of an Objective-C class, the self variable is available along with any instance variables of the class. Instance variables are always writable and do not need to be explicitly declared with __block. But if an instance variable is captured by either reading or writing to it, the self variable is implicitly captured also, because the instance variable relates to that instance. For example, consider following block within a method on a class called EOCClass:

Click here to view code image

@interface EOCClass

- (void)anInstanceMethod {
    // ...
    void (^someBlock)() = ^{
        _anInstanceVariable = @"Something";
        NSLog(@"_anInstanceVariable = %@", _anInstanceVariable);
    };
    // ...
}

@end

The particular instance of EOCClass that had the anInstanceMethod method run on is referred to as the self variable. It is easy to forget that self is captured by this sort of block because it is not used explicitly in the code. However, accessing an instance variable is equivalent to the following:

self->_anInstanceVariable = @"Something";

This is why the self variable is captured. More often than not, properties (see Item 6) will be used to access instance variables, and in this case, the self variable is explicit:

self.aProperty = @"Something";

However, it is important to remember that self is an object and is therefore retained when it is captured by the block. This situation can often lead to retain cycles being introduced if the block is itself retained by the same object to which self refers. See Item 40 for more information.

The Guts of a Block

Every object in Objective-C occupies a certain region of memory. This memory region is a different size for every object, depending on the number of instance variables and associated data contained. A block too is an object itself, since the first variable within the region of memory that a block is defined in is a pointer to a Class object, called the isa pointer (see Item 14). The rest of the memory a block uses contains the various bits of information it needs to function correctly. Figure 6.1 shows the layout of a block in detail.

Figure 6.1 The memory layout of a block object

The most important thing to note in the layout is the variable called invoke, a function pointer to where the implementation of the block resides. The prototype of the function takes at least a void*, which is the block itself. Recall that blocks are a simple replacement for function pointers where state is passed using an opaque void pointer. The block is wrapping up what was previously done using standard C language features into a succinct and simple-to-use interface.

The descriptor variable is a pointer to a structure that each block has, declaring the overall size of the block object and function pointers for copy and dispose helpers. These helpers are run when a block is copied and disposed of, for example, to perform any retaining or releasing, respectively, of captured objects.

Finally, a block contains copies of all the variables it captures. These copies are stored after the descriptor variable and take up as much space as required to store all the captured variables. Note that this does not mean that objects themselves are copied but rather only the variables holding pointers. When the block is run, the captured variables are read from this region of memory, which is why the block needs to be passed as a parameter into the invoke function.

Global, Stack, and Heap Blocks

When blocks are defined, the region of memory they occupy is allocated on the stack. This means that the block is valid only within the scope in which it is defined. For example, the following code is dangerous:

Click here to view code image

void (^block)();
if ( /* some condition */ ) {
    block = ^{
        NSLog(@"Block A");
    };
} else {
    block = ^{
        NSLog(@"Block B");
    };
}
block();

The two blocks that are defined within the if and else statements are allocated within stack memory. When it allocates stack memory for each block, the compiler is free to overwrite this memory at the end of the scope in which that memory was allocated. So each block is guaranteed to be valid only within its respective if-statement section. The code would compile without error but at runtime may or may not function correctly. If it didn’t decide to produce code that overwrote the chosen block, the code would run without error, but if it did, a crash would certainly occur.

To solve this problem, blocks can be copied by sending the block the copy message. In doing so, the block is copied from the stack to the heap. Once this has happened, the block can be used outside the scope in which it was defined. Also, once it has been copied to the heap, a block becomes a reference-counted object. Any subsequent copies do not perform a copy but instead simply increment that block’s reference count. When a heap block is no longer referenced, it needs to be released either automatically, if using ARC, or through an explicit call to release, if using manual reference counting. When the reference count drops to zero, the heap block is deallocated just like any other object is. A stack block does not need to be explicitly released, as this is handled by virtue of the fact that stack memory is automatically reclaimed: the reason that the example code was dangerous.

With this in mind, you can simply apply a couple of copy method calls to make that code safe:

Click here to view code image

void (^block)();
if ( /* some condition */ ) {
    block = [^{
        NSLog(@"Block A");
    } copy];
} else {
    block = [^{
        NSLog(@"Block B");
    } copy];
}
block();

This code is now safe. If manual reference counting were used, the block too would need to be released after it is finished with.

Global blocks are another category, along with stack and heap blocks. Blocks that don’t capture any state, such as variables from the enclosing scope, do not need any state to run. The entire region of memory these blocks use is known in full at compile time; so global blocks are declared within global memory rather than being created on the stack each time they are used. Also, it is a no-op to copy a global block, and a global block is never deallocated. Such blocks are, in effect, singletons. The following is a global block:

Click here to view code image

void (^block)() = ^{
    NSLog(@"This is a block");
};

All the information required to execute this block is known at compile time; therefore, it can be a global block. This is purely an optimization to reduce unnecessary work that might be done if such simple blocks were treated like more complex blocks that require work to be done when they are copied and disposed of.

Things to Remember

Blocks are lexical closures for C, C++, and Objective-C.

Blocks can optionally take parameters and optionally return values.

Blocks can be stack allocated, heap allocated, or global. A stack-allocated block can be copied onto the heap, at which point it is reference counted just like standard Objective-C objects.

Item 38: Create typedefs for Common Block Types

Blocks have an inherent type; that is, they can be assigned to an appropriately typed variable. The type is made up of the parameters the block takes along and with the return type of the block. For example, consider the following block:

^(BOOL flag, int value){
    if (flag) {
        return value * 5;
    } else {
        return value * 10;
    }
}

This block takes two parameters of type BOOL and int and returns a value of type int. If it were to be assigned to a variable, this block would need to be appropriately typed. The type and assignment to the variable would look like this:

Click here to view code image

int (^variableName)(BOOL flag, int value) =
    ^(BOOL flag, int value){
        // Implementation
        return someInt;
    }

This looks quite different from a normal type but should look familiar if you’re used to function pointers. The layout of the type is as follows:

return_type (^block_name)(parameters)

A block-variable definition is different from other types in that the variable name is in the middle of the type rather than on the right. This makes it quite difficult to remember the syntax and to read. For these reasons, it is a good idea to make type definitions for commonly used block types, especially if you are shipping an API that you expect others to use. However, it is possible to hide block types like this behind a name that is easy to read and indicates what the block is meant to do.

To hide the complicated block type, you use a language feature from C called type definitions. The keyword typedef allows you to define an easy-to-read name that becomes an alias for another type. For example, to define a new type for the block that returns an int and takes two parameters—a BOOL and an int—you would use the following type definition:

typedef int(^EOCSomeBlock)(BOOL flag, int value);

Just as the variable name of a block is in the middle prefixed by a caret, so too is the new type name. This adds a new type, called EOCSomeBlock, to the type system. So instead of creating a variable with a complicated type, you can simply use this new type:

Click here to view code image

EOCSomeBlock block = ^(BOOL flag, int value){
    // Implementation
};

This code is now much easier to read, as the variable definition is back to the type on the left and the variable name on the right, just like you’re used to seeing with other variables.

Using this feature can make APIs that use blocks much easier to use. Any class that takes a block as a parameter to a method—for example, a completion handler for an asynchronous task—can make use of this feature to make it a lot easier to read. Consider, for example, a class that has a start method that takes a block as a handler to be run when the task finishes. Without making use of a type definition, the method signature may look like this:

Click here to view code image

- (void)startWithCompletionHandler:
            (void(^)(NSData *data, NSError *error))completion;

Note that the way the syntax for a block type is laid out is different again from that for defining a variable. It’s much easier to read if the type in the method signature is a single word. So you can define a type definition and then use that instead:

Click here to view code image

typedef void(^EOCCompletionHandler)
                           (NSData *data, NSError *error);
- (void)startWithCompletionHandler:
            (EOCCompletionHandler)completion;

This is now much simpler to read and understand what the parameter is. Any good, modern Integrated Development Environment (IDE) will automatically expand the type definition, making this easy to use.

Using a type definition is also useful if you ever need to refactor to change the block’s type signature. For example, if you decide that the completion handler block now needs to take an additional parameter to pass the time the task took, you can simply change the type definition:

Click here to view code image

typedef void(^EOCCompletionHandler)
         (NSData *data, NSTimeInterval duration, NSError *error);

Anywhere the type definition is used, such as method signatures, will now fail to compile in the same way, and you can go through and fix things. Without the type definition, you would find that you needed to change many types throughout your code. It would potentially be easy to miss one or two of these, leading to hard-to-find bugs.

It is usually best to define these type definitions along with the class that uses them. It is also prudent to prefix the new type’s name with the class that uses the type definitions. This makes the block’s use clear. If multiple type definitions end up being created for the same block signature type, fine. It’s better to have more types than fewer.

An example of this point can be seen in the Accounts framework from Mac OS X and iOS. This framework defines, among others, the following block type definitions:

Click here to view code image

typedef void(^ACAccountStoreSaveCompletionHandler)
                                (BOOL success, NSError *error);
typedef void(^ACAccountStoreRequestAccessCompletionHandler)
                                (BOOL granted, NSError *error);

These block type definitions have the same signature but are used in distinct places. The name of the type and the name of the parameters in the signature make it easy for the developer to understand how the type is to be used. The developer could have defined a single type definition, perhaps called ACAccountStoreBooleanCompletionHandler, used in place of both of these. However, that would lose the clarity of how the block and parameters are used.

Similarly, if you have a few classes that perform a similar but distinct asynchronous task but that don’t fit into a class hierarchy, each class should have its own completion handler type. The signature may be exactly the same for each one, but it’s better to use a type definition for each class rather than a single one. On the other hand, if the classes fit into a hierarchy, you could define the type definition along with the base class and have each subclass use it.

Things to Remember

Use type definitions to make it easier to use block variables.

Always follow the naming conventions when defining new types such that you do not clash with other types.

Don’t be afraid to define multiple types for the same block signature. You may want to refactor one place that uses a certain block type by changing the block signature but not another.

Item 39: Use Handler Blocks to Reduce Code Separation

A common paradigm in programming a user interface is to perform tasks asynchronously. In this way, the thread that services user interface display and touches does not get blocked when long-running tasks happen, such as I/O or network activity. This thread is often referred to as the main thread. If such methods were synchronous, the user interface would be unresponsive while the task was occurring. In some circumstances, an application may be automatically terminated if it is unresponsive for a certain time. This is true of iOS applications; the system watchdog will terminate an application whose main thread is blocked for a certain period of time.

Asynchronous methods need a way to notify interested parties that they have finished. This can be achieved in several ways. A commonly used technique is having a delegate protocol (see Item 23) to which an object can conform. The object that is the delegate can be notified when pertinent things happen, such as completion of an asynchronous task.

Consider a class that fetches data from a URL. Using the Delegate pattern, the class may look like this:

Click here to view code image

#import <Foundation/Foundation.h>

@class EOCNetworkFetcher;
@protocol EOCNetworkFetcherDelegate <NSObject>
- (void)networkFetcher:(EOCNetworkFetcher*)networkFetcher
     didFinishWithData:(NSData*)data;
@end

@interface EOCNetworkFetcher : NSObject
@property (nonatomic, weak)
                      id <EOCNetworkFetcherDelegate> delegate;
- (id)initWithURL:(NSURL*)url;
- (void)start;
@end

A class might use this kind of API as follows:

Click here to view code image

- (void)fetchFooData {
    NSURL *url = [[NSURL alloc] initWithString:
                  @"http://www.example.com/foo.dat"];
    EOCNetworkFetcher *fetcher =
        [[EOCNetworkFetcher alloc] initWithURL:url];
    fetcher.delegate = self;
    [fetcher start];
}

// ...

- (void)networkFetcher:(EOCNetworkFetcher*)networkFetcher
     didFinishWithData:(NSData*)data
{
    _fetchedFooData = data;
}

This approach works and is not at all incorrect. However, blocks provide a much cleaner way to achieve the same thing. They can be used to tighten up an API like this and also make it much cleaner for a consumer to use. The idea is to define a block type that is used as the completion handler that is passed directly into the start method:

Click here to view code image

#import <Foundation/Foundation.h>

typedef void(^EOCNetworkFetcherCompletionHandler)(NSData *data);

@interface EOCNetworkFetcher : NSObject
- (id)initWithURL:(NSURL*)url;
- (void)startWithCompletionHandler:
            (EOCNetworkFetcherCompletionHandler)handler;
@end

This is very similar to using a delegate protocol but has an added bonus that the completion handler can be defined inline with the start method call, which greatly improves the readability of code using the network fetcher. For example, consider a class using the completion-block-style API:

Click here to view code image

- (void)fetchFooData {
    NSURL *url = [[NSURL alloc] initWithString:
                  @"http://www.example.com/foo.dat"];
    EOCNetworkFetcher *fetcher =
        [[EOCNetworkFetcher alloc] initWithURL:url];
    [fetcher startWithCompletionHandler:^(NSData *data){
        _fetchedFooData = data;
    }];
}

Comparing this to the code that uses the Delegate pattern should make clear that the block approach is much cleaner. The business logic for what happens when the asynchronous task has finished is sitting right next to the code that starts it. Also, because the block is declared in the same scope as the network fetcher is created, you have access to all the variables that are available in that scope. This is not useful in this simple example but can be extremely useful in more complex scenarios.

A downside to the Delegate approach is that if a class were to use multiple network fetchers to download different bits of data, it would need to switch in the delegate method, based on which network fetcher was calling back. Such code may look like this:

Click here to view code image

- (void)fetchFooData {
    NSURL *url = [[NSURL alloc] initWithString:
                  @"http://www.example.com/foo.dat"];
    _fooFetcher = [[EOCNetworkFetcher alloc] initWithURL:url];
    _fooFetcher.delegate = self;
    [_fooFetcher start];
}

- (void)fetchBarData {
    NSURL *url = [[NSURL alloc] initWithString:
                  @"http://www.example.com/bar.dat"];
    _barFetcher = [[EOCNetworkFetcher alloc] initWithURL:url];
    _barFetcher.delegate = self;
    [_barFetcher start];
}

- (void)networkFetcher:(EOCNetworkFetcher*)networkFetcher
     didFinishWithData:(NSData*)data
{
    if (networkFetcher == _fooFetcher) {
        _fetchedFooData = data;
        _fooFetcher = nil;
    } else if (networkFetcher == _barFetcher) {
        _fetchedBarData = data;
        _barFetcher = nil;
    }
    // etc.
}

In addition to making the delegate callback long, this code means that the network fetchers have to be stored as instance variables to be checked against. Doing so might be required anyway, for other reasons, such as to cancel them later, if required; more often than not, it is a side effect that can quickly clog up a class. The benefit of the block approach is that the network fetchers do not have to be stored, and no switching is required. Rather, the business logic of each completion handler is defined along with each fetcher, like this:

Click here to view code image

- (void)fetchFooData {
    NSURL *url = [[NSURL alloc] initWithString:
                  @"http://www.example.com/foo.dat"];
    EOCNetworkFetcher *fetcher =
        [[EOCNetworkFetcher alloc] initWithURL:url];
    [fetcher startWithCompletionHandler:^(NSData *data){
        _fetchedFooData = data;
    }];
}

- (void)fetchBarData {
    NSURL *url = [[NSURL alloc] initWithString:
                  @"http://www.example.com/bar.dat"];
    EOCNetworkFetcher *fetcher =
        [[EOCNetworkFetcher alloc] initWithURL:url];
    [fetcher startWithCompletionHandler:^(NSData *data){
        _fetchedBarData = data;
    }];
}

As an extension of this, many modern block-based APIs also use a block for error handling. Two approaches can be taken. With the first, a separate handler can be used for failure cases to success cases. With the second, the failure case can be wrapped up into the same completion block. Using a separate handler looks like this:

Click here to view code image

#import <Foundation/Foundation.h>

@class EOCNetworkFetcher;
typedef void(^EOCNetworkFetcherCompletionHandler)(NSData *data);
typedef void(^EOCNetworkFetcherErrorHandler)(NSError *error);

@interface EOCNetworkFetcher : NSObject
- (id)initWithURL:(NSURL*)url;
- (void)startWithCompletionHandler:
            (EOCNetworkFetcherCompletionHandler)completion
        failureHandler:
            (EOCNetworkFetcherErrorHandler)failure;
@end

Code that uses this style of API would look like this:

Click here to view code image

EOCNetworkFetcher *fetcher =
    [[EOCNetworkFetcher alloc] initWithURL:url];
[fetcher startWithCompletionHander:^(NSData *data){
    // Handle success
}
                    failureHandler:^(NSError *error){
    // Handle failure
}];

This style is good because it splits up the success and failure cases, meaning that consumer code too is logically split into success and failure, which helps readability. Also, it’s possible for either failure or success to be ignored, if necessary.

The other style, putting the success and failure in a single block, looks like this:

Click here to view code image

#import <Foundation/Foundation.h>

@class EOCNetworkFetcher;
typedef void(^EOCNetworkFetcherCompletionHandler)
                               (NSData *data, NSError *error);

@interface EOCNetworkFetcher : NSObject
- (id)initWithURL:(NSURL*)url;
- (void)startWithCompletionHandler:
                 (EOCNetworkFetcherCompletionHandler)completion;
@end

Code that uses this style of API would look like this:

Click here to view code image

EOCNetworkFetcher *fetcher =
    [[EOCNetworkFetcher alloc] initWithURL:url];
[fetcher startWithCompletionHander:
    ^(NSData *data, NSError *error){
        if (error) {
            // Handle failure
        } else {
            // Handle success
        }
    }];

This approach requires the error variable to be checked and puts all the logic in one place. The downside is that because all the logic is in one place, the block can become long and complicated. However, the upside of the single-block approach is that it is much more flexible. It’s possible to pass an error, as well as data, for example. Consider that perhaps the network was able to download half the data and then an error occurred. Maybe in that case, you would pass back the data and the associated error. The completion handler can then determine the problem, handle it as appropriate, and may be able to do something useful with the part of the data that was successfully downloaded.

Another good reason for putting success and failure in the same block is that sometimes when processing the data of an otherwise successful response, the consumer detects an error. Perhaps the data returned was too short, for example. This situation may need to be handled in just the same way as the failure case from the network fetcher’s perspective. In that case, having a single block means that processing can be done and that, if an error is found with the data, it can be handled along with the case in which a network fetcher error has been detected. If the success and failure cases are split into separate handlers, it becomes impossible to share the error-handling code of this scenario without deferring to a separate method, which defeats the point of using handler blocks to put business logic code all in one place.

Overall, I suggest using a single handler block for success and failure, which is also the approach that Apple seems to be taking in its APIs. For example, TWRequest from the Twitter framework and MKLocalSearch from the MapKit framework both use the approach of a single handler block.

Another reason to use handler blocks is for calling back at pertinent times. A consumer of the network fetcher may want to be told each time progress is made with the download, for example. This could be done with a delegate. But continuing the theme of using handler blocks instead, you could add a progress-handler block type and a property:

Click here to view code image

typedef void(^EOCNetworkFetcherCompletionHandler)
                                         (float progress);
@property (nonatomic, copy)
              EOCNetworkFetcherProgressHandler progressHandler;

This is a good pattern to follow, as it yet again allows all the business logic to be put in one place: where the network fetcher is created and the completion handler is defined.

Another consideration when writing handler-based APIs stems from the fact that some code is required to run on a certain thread. For instance, any UI work in both Cocoa and Cocoa Touch must happen on the main thread. This equates to the main queue in GCD-land. Therefore, it is sometimes prudent to allow the consumer of a handler-based API to decide on which queue the handler is run. One such API is NSNotificationCenter, which has a method whereby you can register to be notified of a certain notification by the notification center’s executing a certain block. It is possible, but not compulsory, to decide in what queue to schedule the block. If no queue is given, the default behavior is invoked, and the block is run on the thread that posted the notification. The method to add an observer looks like this:

Click here to view code image

- (id)addObserverForName:(NSString*)name
                  object:(id)object
                   queue:(NSOperationQueue*)queue
              usingBlock:(void(^)(NSNotification*))block

Here, an NSOperationQueue is passed in to denote the queue that the block should be run on when a notification is fired. Operation queues rather than the lower-level GCD queues are used, but the semantics are the same. (See Item 43 for more about GCD queues versus other tools.)

You could similarly design an API whereby an operation queue is passed in or even a GCD queue, if that is the level at which you want to pitch the API.

Things to Remember

Use a handler block when it will be useful to have the business logic of the handler be declared inline with the creation of the object.

Handler blocks have the benefit of being associated with an object directly rather than delegation, which often requires switching based on the object if multiple instances are being observed.

When designing an API that uses handler blocks, consider passing a queue as a parameter, to designate the queue on which the block should be enqueued.

Item 40: Avoid Retain Cycles Introduced by Blocks Referencing the Object Owning Them

Blocks can very easily introduce retain cycles if they are not considered carefully. For example, the following class provides an interface for downloading a certain URL. A callback block, called a completion handler, can be set when the fetcher is started and is run when the download has finished. The completion handler needs to be stored in an instance variable in order to be available when the request-completion method is called.

Click here to view code image

// EOCNetworkFetcher.h
#import <Foundation/Foundation.h>

typedef void(^EOCNetworkFetcherCompletionHandler)(NSData *data);

@interface EOCNetworkFetcher : NSObject
@property (nonatomic, strong, readonly) NSURL *url;
- (id)initWithURL:(NSURL*)url;
- (void)startWithCompletionHandler:
            (EOCNetworkFetcherCompletionHandler)completion;
@end


// EOCNetworkFetcher.m
#import "EOCNetworkFetcher.h"

@interface EOCNetworkFetcher ()
@property (nonatomic, strong, readwrite) NSURL *url;
@property (nonatomic, copy)
          EOCNetworkFetcherCompletionHandler completionHandler;
@property (nonatomic, strong) NSData *downloadedData;
@end

@implementation EOCNetworkFetcher

- (id)initWithURL:(NSURL*)url {
    if ((self = [super init])) {
        _url = url;
    }
    return self;
}

- (void)startWithCompletionHandler:
        (EOCNetworkFetcherCompletionHandler)completion
{
    self.completionHandler = completion;
    // Start the request
    // Request sets downloadedData property
    // When request is finished, p_requestCompleted is called
}

- (void)p_requestCompleted {
    if (_completionHandler) {
        _completionHandler(_downloadedData);
    }
}

@end

Another class may create one of these network fetcher objects and use it to download data at a URL, like this:

Click here to view code image

@implementation EOCClass {
    EOCNetworkFetcher *_networkFetcher;
    NSData *_fetchedData;
}

- (void)downloadData {
    NSURL *url = [[NSURL alloc] initWithString:
                  @"http://www.example.com/something.dat"];
    _networkFetcher =
        [[EOCNetworkFetcher alloc] initWithURL:url];
    [_networkFetcher startWithCompletionHandler:^(NSData *data){
        NSLog(@"Request URL %@ finished", _networkFetcher.url);
        _fetchedData = data;
    }];
}

@end

This code looks fairly normal. But you may have failed to realize that a retain cycle is present. It stems from the fact that the completion-handler block references the self variable because it sets the _fetchedData instance variable (see Item 37 for more about captured variables). This means that the EOCClass instance that creates the network fetcher is retained by the block. This block is retained by the network fetcher, which is in turn retained by the same instance of EOCClass because it is held within a strong instance variable. Figure 6.2 illustrates this retain cycle.

Figure 6.2 Retain cycle between the network fetcher and the class that owns it

This retain cycle can easily be fixed by breaking either the reference the _networkFetcher instance variable holds or the one the completionHandler property holds. This break would need to be done when the completion handler has finished in the case of this network fetcher, so the network fetcher is alive until it has finished. For example, the completion-handler block could be changed to this:

Click here to view code image

[_networkFetcher startWithCompletionHandler:^(NSData *data){
    NSLog(@"Request for URL %@ finished", _networkFetcher.url);
    _fetchedData = data;
    _networkFetcher = nil;
}

This retain-cycle problem is common in APIs that make use of completion callback blocks and is therefore important to understand. Often, the problem can be solved by clearing one of the references at an opportune moment; however, it cannot always be guaranteed that the moment will occur. In the example, the retain cycle is broken only if the completion handler is run. If the completion handler was never run, the retain cycle would never be broken, and leaks would occur.

Another potential retain cycle can be introduced with the completion-handler block approach. This retain cycle occurs when the completion-handler block references the object that ends up owning it. For example, to extend the previous example, instead of the consumer having to keep a reference to the network fetcher while it is running, it has a mechanism for staying alive itself. The network fetcher may do this by adding itself to a global collection, such as a set, when it is started and removing itself when it finishes. The consumer could then change its code to the following:

Click here to view code image

- (void)downloadData {
    NSURL *url = [[NSURL alloc] initWithString:
                  @"http://www.example.com/something.dat"];
    EOCNetworkFetcher *networkFetcher =
        [[EOCNetworkFetcher alloc] initWithURL:url];
    [networkFetcher startWithCompletionHandler:^(NSData *data){
        NSLog(@"Request URL %@ finished", networkFetcher.url);
        _fetchedData = data;
    }];
}

Most networking libraries use this kind of approach, as it is annoying to have to keep the fetcher object alive yourself. An example is the TWRequest object from the Twitter framework. However, as the code for EOCNetworkFetcher stands, a retain cycle remains. It is more subtle than before, though, and stems from the fact that the completion-handler block references the request itself. The block therefore retains the fetcher, which in turn retains the block through the completionHandler property. Fortunately, the fix is simple. Recall that the completion handler was being kept in a property only so that it could be used later. The problem is that once the completion handler has been run, it no longer needs to hold onto the block. So the simple fix is to change the following method:

Click here to view code image

- (void)p_requestCompleted {
    if (_completionHandler) {
        _completionHandler(_downloadedData);
    }
    self.completionHandler = nil;
}

The retain cycle is then broken once the request has completed, and the fetcher object will be deallocated as necessary. Note that this is a good reason to pass the completion handler in the start method. If instead the completion handler were exposed as a public property, you couldn’t just go and clear it when the request completed, as that would break the encapsulation semantics you have given the consumer by saying that the completion handler is public. In this case, the only way to break the retain cycle sensibly is by enforcing that the consumer clear the completionHandler property in the handler itself. But that is not very sensible, because you cannot assume that a consumer will do this and will instead blame you for the leaks.

Both of these scenarios are not uncommon. They are bugs that are easy to creep in when using blocks; similarly, they are just as easy to mitigate if you are careful. The key is to think about what objects a block may capture and therefore retain. If any of these can be an object that retains the block, either directly or indirectly, you will need to think about how to break the retain cycle at the correct moment.

Things to Remember

Be aware of the potential problem of retain cycles introduced by blocks that capture objects that directly or indirectly retain the block.

Ensure that retain cycles are broken at an opportune moment, but never leave responsibility to the consumer of your API.

Item 41: Prefer Dispatch Queues to Locks for Synchronization

Sometimes in Objective-C, you will come across code that you’re having trouble with because it’s being accessed from multiple threads. This situation usually calls for the application of some sort of synchronization through the use of locks. Before GCD, there were two ways to achieve this, the first being the built-in synchronization block:

Click here to view code image

- (void)synchronizedMethod {
    @synchronized(self) {
        // Safe
    }
}

This construct automatically creates a lock based on the given object and waits on that lock until it executes the code contained in the block. At the end of the code block, the lock is released. In the example, the object being synchronized against is self. This construct is often a good choice, as it ensures that each instance of the object can run its own synchronizedMethod independently. However, overuse of @synchronized(self) can lead to inefficient code, as each synchronized block will execute serially across all such blocks. If you overuse synchronization against self, you can end up with code waiting unnecessarily on a lock held by unrelated code.

The other approach is to use the NSLock object directly:

Click here to view code image

_lock = [[NSLock alloc] init];

- (void)synchronizedMethod {
    [_lock lock];
    // Safe
    [_lock unlock];
}

Recursive locks are also available through NSRecursiveLock, allowing for one thread to take out the same lock multiple times without causing a deadlock.

Both of these approaches are fine but come with their own drawbacks. For example, synchronization blocks can suffer from deadlock under extreme circumstances and are not necessarily efficient. Direct use of locks can be troublesome when it comes to deadlocks.

The alternative is to use GCD, which can provide locking in a much simpler and more efficient manner. Properties are a good example of where developers find the need to put synchronization, known as making the property atomic. This can be achieved through use of the atomic property attribute (see Item 6). Or, if the accessors need to be written manually, the following is often seen:

Click here to view code image

- (NSString*)someString {
    @synchronized(self) {
        return _someString;
    }
}

- (void)setSomeString:(NSString*)someString {
    @synchronized(self) {
        _someString = someString;
    }
}

Recall that @synchronized(self) is dangerous if overused, because all such blocks will be synchronized with respect to one another. If multiple properties do that, each will be synchronized with respect to all others, which is probably not what you want. All you really want is that access to each property be synchronized individually.

As an aside, you should be aware that although this goes some way to ensuring thread safety, it does not ensure absolute thread safety of the object. Rather, access to the property is atomic. You are guaranteed to get valid results when using the property, but if you call the getter multiple times from the same thread, you may not necessarily get the same result each time. Other threads may have written to the property between accesses.

A simple and effective alternative to synchronization blocks or lock objects is to use a serial synchronization queue. Dispatching reads and writes onto the same queue ensures synchronization. Doing so looks like this:

Click here to view code image

_syncQueue =
dispatch_queue_create("com.effectiveobjectivec.syncQueue", NULL);

- (NSString*)someString {
    __block NSString *localSomeString;
    dispatch_sync(_syncQueue, ^{
        localSomeString = _someString;
    });
    return localSomeString;
}

- (void)setSomeString:(NSString*)someString {
    dispatch_sync(_syncQueue, ^{
        _someString = someString;
    });
}

The idea behind this pattern is that all access to the property is synchronized because the GCD queue that both the setter and the getter run on is a serial queue. Apart from the __block syntax in the getter, required to allow the block to set the variable (see Item 37), this approach is much neater. All the locking is handled down in GCD, which has been implemented at a very low level and has many optimizations made. Thus, you don’t have to worry about that side of things and can instead focus on writing your accessor code.

However, we can go one step further. The setter does not have to be synchronous. The block that sets the instance variable does not need to return anything to the setter method. This means that you can change the setter method to look like this:

Click here to view code image

- (void)setSomeString:(NSString*)someString {
    dispatch_async(_syncQueue, ^{
        _someString = someString;
    });
}

The simple change from synchronous dispatch to asynchronous provides the benefit that the setter is fast from the caller’s perspective, but reading and writing are still executed serially with respect to each another. One downside, though, is that if you were to benchmark this, you might find that it’s slower; with asynchronous dispatch, the block has to be copied. If the time taken to perform the copy is significant compared to the time the block takes to execute, it will be slower. So in our simple example, it’s likely to be slower. However, the approach is still good to understand as a potential candidate if the block that is being dispatched performs much heavier tasks.

Another way to make this approach even faster is to take advantage of the fact that the getters can run concurrently with one another but not with the setter. This is where the GCD approach comes into its own. The following cannot be easily done with synchronization blocks or locks. Instead of using a serial queue, consider what would happen if you used a concurrent queue:

Click here to view code image

_syncQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

- (NSString*)someString {
    __block NSString *localSomeString;
    dispatch_sync(_syncQueue, ^{
        localSomeString = _someString;
    });
    return localSomeString;
}

- (void)setSomeString:(NSString*)someString {
    dispatch_async(_syncQueue, ^{
        _someString = someString;
    });
}

As it stands, that code would not work for synchronization. All reads and writes are executed on the same queue, but that queue being concurrent, reads and writes can all happen at the same time. This is what we were trying to stop from happening in the first place! However, a simple GCD feature, called a barrier, is available and can solve this. The functions that a queue barrier blocks are as follows:

Click here to view code image

void dispatch_barrier_async(dispatch_queue_t queue,
                            dispatch_block_t block);
void dispatch_barrier_sync(dispatch_queue_t queue,
                           dispatch_block_t block);

A barrier is executed exclusively with respect to all other blocks on that queue. They are relevant only on concurrent queues, since all blocks on a serial queue are always executed exclusively with respect to one another. When a queue is processed and the next block is a barrier block, the queue waits for all current blocks to finish and then executes the barrier block. When the barrier block finishes executing, processing of the queue continues as normal.

Barriers can be used with the property example in the setter. If the setter uses a barrier block, reads of the property will still execute concurrently, but writes will execute exclusively. Figure 6.3 illustrates the queue with many reads and a single write queued.

Figure 6.3 Concurrent queue with reads as normal blocks and writes as barrier blocks. Reads are executed concurrently; writes are executed exclusively, as they are barriers.

The code to achieve this is simple:

Click here to view code image

_syncQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

- (NSString*)someString {
    __block NSString *localSomeString;
    dispatch_sync(_syncQueue, ^{
        localSomeString = _someString;
    });
    return localSomeString;
}

- (void)setSomeString:(NSString*)someString {
    dispatch_barrier_async(_syncQueue, ^{
        _someString = someString;
    });
}

If you were to benchmark this, you would certainly find it quicker than using a serial queue. Note that you could also use a synchronous barrier in the setter, which may be more efficient for the same reason as explained before. It would be prudent to benchmark each approach and choose the one that is best for your specific scenario.

Things to Remember

Dispatch queues can be used to provide synchronization semantics and offer a simpler alternative to @synchronized blocks or NSLock objects.

Mixing synchronous and asynchronous dispatches can provide the same synchronized behavior as with normal locking but without blocking the calling thread in the asynchronous dispatches.

Concurrent queues and barrier blocks can be used to make synchronized behavior more efficient.

Item 42: Prefer GCD to performSelector and Friends

Thanks to the extremely dynamic nature of Objective-C (see Item 11), a few methods defined on NSObject allow you to call any method you wish. They allow delayed execution of a method call or specification of which thread it should be run on. They were once a very useful feature; now, however, technologies such as Grand Central Dispatch and blocks are making their use less important. Although you will often still see code using them, I encourage you to stay clear of them.

The most basic method in this family is performSelector:. It takes a single argument, which is the selector to perform, with the following signature:

- (id)performSelector:(SEL)selector

This is equivalent to calling the selector directly. So the following two lines of code are equivalent:

Click here to view code image

[object performSelector:@selector(selectorName)];
[object selectorName];

It might seem as though this is redundant. It would be if this were the only way the method could be used. However, its real power comes from the fact that the selector can be decided at runtime. Such dynamic binding on top of dynamic binding means that you can do something like this:

Click here to view code image

SEL selector;
if ( /* some condition */ ) {
    selector = @selector(foo);
} else if ( /* some other condition */ ) {
    selector = @selector(bar);
} else {
    selector = @selector(baz);
}
[object performSelector:selector];

This code is extremely flexible and can often be used to simplify complex code. Another use is to store a selector that should be performed after an event has happened. In either case, the compiler doesn’t know until runtime which selector is going to be performed. But the cost of this feature is that if you compile this under ARC, the compiler emits the following warning:

Click here to view code image

warning: performSelector may cause a leak because its selector
is unknown [-Warc-performSelector-leaks]

You probably weren’t expecting that! If you were, you probably know why you should be careful with these methods. This message may look strange to you, and you’re wondering why a leak is mentioned. After all, you were simply trying to call a method. The reason is that the compiler doesn’t know what selector is going to be invoked and therefore doesn’t know the method signature, the return type, or even if there is a returned value. Also, the compiler doesn’t know the method name and therefore cannot apply ARC’s memory-management rules to determine whether the return value should be released. For this reason, ARC plays it safe and doesn’t add a release. However, the result might be a memory leak, as the object might be being returned as a retained object.

Consider the following code:

Click here to view code image

SEL selector;
if ( /* some condition */ ) {
    selector = @selector(newObject);
} else if ( /* some other condition */ ) {
    selector = @selector(copy);
} else {
    selector = @selector(someProperty);
}
id ret = [object performSelector:selector];

This is a slight variation on the preceding example to show the problem. In the case of the first two selectors, the ret object would need to be released by this code; with the third selector, it would not. This is true not only in an ARC world but also in a non-ARC world, which is strictly following the method-naming guidelines. Without ARC (and therefore no compiler warning), the ret object would need to be released if either of the first two conditions were true but not otherwise. This could easily be overlooked, and even a static analyzer would not help detect the subsequent memory leak. This is one reason for treating the performSelector family of methods with caution.

Another reason these methods are not ideal is that the return type can be only void or an object type. The performSelector method’s return type is id, although it’s also valid that the selector being performed returns void. Although intricate casting can use selectors that return other values, such as integers or floats, it can be fragile. It’s technically possible to return any type that has the same size as a pointer, as the id type is a pointer to any Objective-C object: on 32-bit architectures, any type that is 32 bits wide; on 64-bit architectures, any type that is 64 bits wide. If the return type is a C struct, the performSelector method cannot be used.

A couple of other performSelector variants that can pass arguments with the message are defined as follows:

Click here to view code image

- (id)performSelector:(SEL)selector
           withObject:(id)object
- (id)performSelector:(SEL)selector
           withObject:(id)objectA
           withObject:(id)objectB

For example, these variants can be used to set a property called value on an object:

Click here to view code image

id object = /* an object with a property called 'value' */;
id newValue = /* new value for the property */;
[object performSelector:@selector(setValue:)
             withObject:newValue];

These methods may seem useful, but they have serious limitations. The objects being passed in must be objects, as the type is always id. So if the selector takes an integer or a float, these methods cannot be used. In addition, the selector can take a maximum of two parameters, using the method performSelector:withObject:withObject:. There are no equivalent methods to perform selectors that take more than two parameters.

One of the other features of the performSelector family of methods is the fact that the selector can be run after a delay or on another thread. Some of the more common of these methods are as follows:

Click here to view code image

- (void)performSelector:(SEL)selector
             withObject:(id)argument
             afterDelay:(NSTimeInterval)delay
- (void)performSelector:(SEL)selector
               onThread:(NSThread*)thread
             withObject:(id)argument
          waitUntilDone:(BOOL)wait
- (void)performSelectorOnMainThread:(SEL)selector
                         withObject:(id)argument
                      waitUntilDone:(BOOL)wait

However, these methods soon become too constraining. For example, there is no method to perform a given selector that takes two arguments after a delay. The threading methods are not very generic, for the same reason. Code that wants to make use of these methods often packs multiple arguments into a dictionary and unpacks in the called method, thereby adding overhead and the potential for bugs.

All these limitations are solved by using one of the alternatives. The main alternative is using blocks (see Item 37). Furthermore, using blocks with Grand Central Dispatch (GCD) enables you to achieve all the threading-related reasons for using one of the performSelector methods. Performing after a delay can be achieved with dispatch_after, and performing on another thread can be achieved with dispatch_sync and dispatch_async.

For example, to perform a task after a delay, you should prefer the latter to the former:

Click here to view code image

// Using performSelector:withObject:afterDelay:
[self performSelector:@selector(doSomething)
           withObject:nil
           afterDelay:5.0];

// Using dispatch_after
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,
                                (int64_t)(5.0 * NSEC_PER_SEC));
dispatch_after(time, dispatch_get_main_queue(), ^(void){
    [self doSomething];
});

To perform a task on the main thread:

Click here to view code image

// Using performSelectorOnMainThread:withObject:waitUntilDone:
[self performSelectorOnMainThread:@selector(doSomething)
                       withObject:nil
                    waitUntilDone:NO];

// Using dispatch_async
// (or if waitUntilDone is YES, then dispatch_sync)
dispatch_async(dispatch_get_main_queue(), ^{
    [self doSomething];
});

Things to Remember

The performSelector family of methods is potentially dangerous with respect to memory management. If it has no way of determining what selector is going to be performed, the ARC compiler cannot insert the appropriate memory-management calls.

The family of methods is very limited with respect to the return type and the number of parameters that can be sent to the method.

The methods that allow performing a selector on a different thread are better replaced with certain Grand Central Dispatch (GCD) calls using blocks.

Item 43: Know When to Use GCD and When to Use Operation Queues

GCD is a fantastic technology, but it is sometimes better to use other tools that come as part of the standard system libraries. Knowing when to use each tool is important; using the wrong tool can lead to code that’s difficult to maintain.

The synchronization mechanisms of GCD (see Item 41) can hardly be rivaled. The same goes for single-time code execution through the use of dispatch_once (see Item 45). However, using GCD is not always the best approach for executing tasks in the background. A separate but related technology, NSOperationQueue, allows you to queue operations (subclasses of NSOperation) that can optionally run concurrently. The similarity to GCD’s dispatch queues is not a coincidence. Operation queues came before GCD, but there is no doubt that GCD is based on the principles made popular by operation queues. In fact, from iOS 4 and Mac OS X 10.6 onward, operation queues use GCD under the hood.

The first difference to note is that GCD is a pure C API, whereas operation queues are Objective-C objects. In GCD, the task that is queued is a block, which is a fairly lightweight data structure (see Item 37). Operations, on the other hand, are Objective-C objects and are therefore more heavyweight. That said, GCD is not always the approach of choice. Sometimes, this overhead is minimal, and the benefits of using full objects far outweigh the downsides.

Through the use of the NSBlockOperation or NSOperationQueue’s addOperationWithBlock: method, the syntax of operation queues can look very similar to plain GCD. Here are some of the benefits of NSOperation and NSOperationQueue:

Cancelling operations

With operation queues, this is simple. When run, the cancel method on NSOperation sets internal flags within the operation to tell it not to run, although it cannot cancel an operation that has already started. On the other hand, GCD queues have no way of cancelling a block once it is scheduled. The architecture is very much “fire and forget.” Implementing cancelling at the application level, however, would be possible but would require writing a lot of code that has already been written in the form of operations.

Operation dependencies

An operation can have dependencies on as many other operations as it wishes. This enables you to create a hierarchy of operations dictating that certain operations can execute only after another operation has completed successfully. For example, you may have operations to download and process files from a server that requires a manifest file to be downloaded first before others can be processed. The operation to download the manifest file first could be a dependency of the subsequent download operations. If the operation queue were set to allow concurrent execution, the subsequent downloads could execute in parallel but only after the dependent operation had completed.

Key-Value Observing of operation properties

Operations have many properties that are appropriate for KVO, such as isCancelled to determine whether it has been cancelled and isFinished to determine whether it has finished. Using KVO can be useful if you have code that wants to know when a certain task changes state and gives much finer-grained control than GCD over the tasks that are operating.

Operation priorities

An operation has an associated priority that ranks it against other operations in a queue. Higher-priority operations are executed before lower-priority ones. The scheduling algorithm is opaque but most certainly will have been carefully thought out. GCD has no direct way of achieving the same thing. It does have queue priorities, but they set a priority for the entire queue rather than individual blocks. Writing your own scheduler on top of this is not something you really want to do. Priorities are therefore a useful feature of operations.

Operations also have an associated thread priority, which determines at what priority the thread will execute when the operation runs. You could do this yourself with GCD, but operations make it as simple as setting a property.

Reuse of operations

Unless you use one of the built-in concrete subclasses of NSOperation, such as NSBlockOperation, you must create your own subclass. This class, being a normal Objective-C object, can store whatever information you want. When it runs, it has full use of this information and any methods that have been defined on the class. This makes it much more powerful than a simple block that is queued on a dispatch queue. These operation classes can be reused throughout your code, thereby following the “Don’t Repeat Yourself” (DRY) principle of software development.

As you can see, there are many good reasons to use operation queues over dispatch queues. Operation queues mostly provide instant solutions to many of the things you might want to do when executing tasks. Instead of writing complex schedulers, or cancel semantics or priorities yourself, you get them for free when using operation queues.

One API that makes use of operation queues rather than dispatch queues is NSNotificationCenter, which has a method where you can register to observe a notification through a block instead of calling a selector. The method prototype looks like this:

Click here to view code image

- (id)addObserverForName:(NSString*)name
                  object:(id)object
                   queue:(NSOperationQueue*)queue
              usingBlock:(void(^)(NSNotification*))block

Instead of taking an operation queue, this method could have taken a dispatch queue on which to queue the notification-handler block. But clearly, the design decision was made to make use of the higher-level Objective-C API. In this case, there is little difference between the two in terms of efficiency. The decision was possibly made because using a dispatch queue would introduce an unnecessary dependency on GCD; remember that blocks are not GCD, so the block itself does not introduce this dependency. Or perhaps the developers wanted to keep it all in Objective-C.

You will often hear that you should always use the highest-level API possible, dropping down only when truly necessary. I subscribe to this mantra but with caution. Just because it can be done with the high-level Objective-C variant does not necessarily mean that it’s better. Benchmarking is always the best way to know for sure what is best.

Things to Remember

Dispatch queues are not the only solution to multithreading and task management.

Operation queues provide a high-level, Objective-C API that can do most of what plain GCD can do. These queues can also do much more complex things that would require additional code on top of GCD.

Item 44: Use Dispatch Groups to Take Advantage of Platform Scaling

Dispatch groups are a GCD feature that allows you to easily group tasks. You can then wait on that set of tasks to finish or be notified through a callback when the set of tasks has finished. This feature is very useful for several reasons, the first and most interesting of which is when you want to perform multiple tasks concurrently but need to know when they have all finished. An example of this would be performing a task, such as compressing a set of files.

A dispatch group is created with the following function:

dispatch_group_t dispatch_group_create();

A group is a simple data structure with nothing distinguishing it, unlike a dispatch queue, which has an identifier. You can associate tasks with a dispatch group in two ways. The first is to use the following function:

Click here to view code image

void dispatch_group_async(dispatch_group_t group,
                          dispatch_queue_t queue,
                          dispatch_block_t block);

This is a variant of the normal dispatch_async function but takes an additional group parameter, which specifies the group with which to associate the block to execute. The second way to associate a task with a dispatch group is to use the following pair of functions:

Click here to view code image

void dispatch_group_enter(dispatch_group_t group);
void dispatch_group_leave(dispatch_group_t group);

The former causes the number of tasks the group thinks are currently running to increment; the latter does the opposite. Therefore, for each call to dispatch_group_enter, there must be an associated dispatch_group_leave. This is similar to reference counting (see Item 29), whereby retains and releases must be balanced to avoid leaks. In the case of dispatch groups, if an enter is not balanced with a leave, the group will never finish.

The following function can be used to wait on a dispatch group to finish:

Click here to view code image

long dispatch_group_wait(dispatch_group_t group,
                         dispatch_time_t timeout);

This takes the group to wait on and a timeout value. The timeout specifies how long this function should block while waiting for the group to finish. If the group finishes before the timeout, zero is returned; otherwise, a nonzero value is returned. The constant DISPATCH_TIME_FOREVER can be used as the timeout value to indicate that the function should wait forever and never time out.

The following function is an alternative to blocking the current thread to wait for a dispatch group to finish:

Click here to view code image

void dispatch_group_notify(dispatch_group_t group,
                           dispatch_queue_t queue,
                           dispatch_block_t block);

Slightly different from the wait function, this function allows you to specify a block that will be run on a certain queue when the group is finished. Doing so can be useful if the current thread should not be blocked, but you still need to know when all the tasks have finished. In both Mac OS X and iOS, for example, you should never block the main thread, as that’s where all UI drawing and event handling are done.

An example of using this GCD feature is to perform a task on an array of objects and then wait for all tasks to finish. The following code does this:

Click here to view code image

dispatch_queue_t queue =
  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t dispatchGroup = dispatch_group_create();
for (id object in collection) {
    dispatch_group_async(dispatchGroup,
                         queue,
                         ^{ [object performTask]; });
}

dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER);
// Continue processing after completing tasks

If the current thread should not be blocked, you can use the notify function instead of waiting:

Click here to view code image

dispatch_queue_t notifyQueue = dispatch_get_main_queue();
dispatch_group_notify(dispatchGroup,
                      notifyQueue,
                      ^{
                    // Continue processing after completing tasks
                       });

The queue on which the notify callback should be queued is entirely dependent on circumstances. Here, I’ve shown it being the main queue, which would be a fairly common use case. But it could also be any custom serial queue or one of the global concurrent queues.

In this example, the queue dispatched onto was the same one for all tasks. But this doesn’t have to be the case. You may want to put some tasks at a higher priority but still group them all into the same dispatch group and be notified when all have finished:

Click here to view code image

dispatch_queue_t lowPriorityQueue =

  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t highPriorityQueue =
  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t dispatchGroup = dispatch_group_create();

for (id object in lowPriorityObjects) {
    dispatch_group_async(dispatchGroup,
                         lowPriorityQueue,
                         ^{ [object performTask]; });
}

for (id object in highPriorityObjects) {
    dispatch_group_async(dispatchGroup,
                         highPriorityQueue,
                         ^{ [object performTask]; });
}

dispatch_queue_t notifyQueue = dispatch_get_main_queue();
dispatch_group_notify(dispatchGroup,
                      notifyQueue,
                      ^{
                    // Continue processing after completing tasks
                       });

Instead of submitting tasks to concurrent queues as in the preceding examples, you may instead use dispatch groups to track multiple tasks submitted to different serial queues. However, a group is not particularly useful if all tasks are queued on the same serial queue. Because the tasks will all execute serially anyway, you could simply queue another block after queuing the tasks, which is the equivalent of a dispatch group’s notify callback block:

Click here to view code image

dispatch_queue_t queue =
dispatch_queue_create("com.effectiveobjectivec.queue", NULL);

for (id object in collection) {
    dispatch_async(queue,
                   ^{ [object performTask]; });
}

dispatch_async(queue,
               ^{
                    // Continue processing after completing tasks
                });

This code shows that you don’t always need to use something like dispatch groups. Sometimes, the desired effect can be achieved by using a single queue and standard asynchronous dispatch.

Why did I mention performing tasks based on system resources? Well, if you look back to the example of dispatching onto a concurrent queue, it should become clear. GCD automatically creates new threads or reuses old ones as it sees fit to service blocks on a queue. In the case of concurrent queues, this can be multiple threads, meaning that multiple blocks are executed concurrently. The number of concurrent threads processing a given concurrent queue depends on factors, mostly based on system resources, that GCD decides. If the CPU has multiple cores, a queue having a lot of work to do will likely be given multiple threads on which to execute. Dispatch groups provide an easy way to perform a given set of tasks concurrently and be told when that group of tasks has finished. Through the nature of GCD’s concurrent queues, the tasks will be executed concurrently and based on available system resources. This leaves you to code your business logic and not have to write any kind of complex scheduler to handle concurrent tasks.

The example of looping through a collection and performing a task on each item can also be achieved through the use of another GCD function, as follows:

Click here to view code image

void dispatch_apply(size_t iterations,
                    dispatch_queue_t queue,
                    void(^block)(size_t));

This function performs a given number of iterations of a block, each time passing an incrementing value from zero to the number of iterations minus one. It is used like this:

Click here to view code image

dispatch_queue_t queue =
  dispatch_queue_create("com.effectiveobjectivec.queue", NULL);
dispatch_apply(10, queue, ^(size_t i){
    // Perform task
});

In effect, this is equivalent to a simple for loop that iterates from 0 to 9, like this:

Click here to view code image

for (int i = 0; i < 10; i++) {
    // Perform task
}

The key thing to note with dispatch_apply is that the queue could be a concurrent queue. If so, the blocks will be executed in parallel according to system resources, just like the example of dispatch groups. If the collection in that example were an array, it could be rewritten using dispatch_apply like this:

Click here to view code image

dispatch_queue_t queue =
  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_apply(array.count, queue, ^(size_t i){
    id object = array[i];
    [object performTask];
});

Once again, this example shows that dispatch groups are not always necessary. However, dispatch_apply blocks until all iterations have finished. For this reason, if you try to run blocks on the current queue (or a serial queue above the current queue in the hierarchy), a deadlock will result. If you want the tasks to be executed in the background, you need to use dispatch groups.

Things to Remember

Dispatch groups are used to group a set of tasks. You can optionally be notified when the group finishes executing.

Dispatch groups can be used to execute multiple tasks concurrently through a concurrent dispatch queue. In this case, GCD handles the scheduling of multiple tasks at the same time, based on system resources. Writing this yourself would require a lot of code.

Item 45: Use dispatch_once for Thread-Safe Single-Time Code Execution

The Singleton design pattern—no stranger in the Objective-C world—is usually achieved through a class method called something like sharedInstance, which returns the singleton instance of a class instead of specifically allocating a new instance each time. A common implementation of the shared-instance method for a class called EOCClass is the following:

Click here to view code image

@implementation EOCClass

+ (id)sharedInstance {
    static EOCClass *sharedInstance = nil;
    @synchronized(self) {
        if (!sharedInstance) {
            sharedInstance = [[self alloc] init];
        }
    }
    return sharedInstance;
}

@end

I have found that the Singleton pattern generates hot debate, especially in Objective-C. Thread safety is the primary candidate for debate. The preceding code creates the singleton instance enclosed in a synchronization block to make it thread safe. For better or worse, the pattern is commonly used, and such code is commonplace.

However, GCD introduced a feature that makes singleton instances much easier to implement. The function is as follows:

Click here to view code image

void dispatch_once(dispatch_once_t *token,
                   dispatch_block_t block);

This function takes a special dispatch_once_t type, which I will call the “token,” and a block. The function ensures that for a given token, the block is executed once and only once. The block is always executed the first time and, most important, is entirely thread safe. Note that the token passed in needs to be exactly the same one for each block that should be executed once. This usually means declaring the token variable in static or global scope.

Rewriting the singleton shared-instance method with this function looks like this:

Click here to view code image

+ (id)sharedInstance {
    static EOCClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

Using dispatch_once simplifies the code and ensures thread safety entirely, so you don’t even have to think about locking or synchronization. All that is handled in the depths of GCD. The token has been declared static because it needs to be exactly the same token each time. Defining the variable in static scope means that the compiler ensures that instead of creating a new variable each time the sharedInstance method is run, only a single variable is reused each time.

Furthermore, dispatch_once is more efficient. Instead of using a heavyweight synchronization mechanism, which acquires a lock every time the code is run, it uses atomic access to the dispatch token to indicate whether the code has been run yet. A simple benchmark on my 64-bit, Mac OS X 10.8.2 machine, accessing the sharedInstance method using the @synchronized approach versus the dispatch_once approach, showed an almost doubled speedup using dispatch_once.

Things to Remember

Thread-safe single-code execution is a common task. GCD provides an easy-to-use tool for this with the dispatch_once function.

The token should be declared in static or global scope such that it is the same token being passed in for each block that should be executed once.

Item 46: Avoid dispatch_get_current_queue

When using GCD and especially when dispatching onto various queues, it is common to need to determine which queue is currently being executed. For example, UI work in both Mac OS X and iOS needs to be performed on the main thread, which equates to the main queue in GCD. Sometimes, it seems necessary to determine whether the current code is being executed on the main queue. Reading through the documentation, you would come across the following function:

dispatch_queue_t dispatch_get_current_queue()

This is documented to return the current queue that is being executed. That is exactly what the function does, but it should be treated with caution. In fact, it is now officially deprecated in iOS as of version 6.0. But it is not deprecated in Mac OS X as of version 10.8. Nevertheless, it should still be avoided on Mac OS X.

A typical antipattern that has become a common use of this method is to check the current queue against a specific queue to try to work around a deadlock that can occur if dispatching synchronously. Consider the following accessor methods, which use a queue to synchronize access to an instance variable (see Item 41):

Click here to view code image

- (NSString*)someString {
    __block NSString *localSomeString;
    dispatch_sync(_syncQueue, ^{
        localSomeString = _someString;
    });
    return localSomeString;
}

- (void)setSomeString:(NSString*)someString {
    dispatch_async(_syncQueue, ^{
        _someString = someString;
    });
}

A problem you may encounter with this pattern is a deadlock in the getter, if the getter is called from the same queue as the queue used for synchronization (_syncQueue in the example), because dispatch_sync won’t return until the block has executed in full. But if the target queue for the block is the current queue, the block will never get a chance to run, because dispatch_sync will continue to block, waiting for the queue to become available to run the target block. This is an example of a method that is not reentrant.

Having read the documentation for dispatch_get_current_queue, you may think that it would be safe to make the method reentrant by checking whether the current queue is the synchronization queue and, if so, simply execute the block directly rather than dispatching, as follows:

Click here to view code image

- (NSString*)someString {
    __block NSString *localSomeString;
    dispatch_block_t accessorBlock = ^{
        localSomeString = _someString;
    };

    if (dispatch_get_current_queue() == _syncQueue) {
        accessorBlock();
    } else {
        dispatch_sync(_syncQueue, accessorBlock);
    }

    return localSomeString;
}

This would probably work for you under simple circumstances. However, it is dangerous and can still deadlock. To see why, consider the following scenario with two serial dispatch queues:

Click here to view code image

dispatch_queue_t queueA =
  dispatch_queue_create("com.effectiveobjectivec.queueA", NULL);
dispatch_queue_t queueB =
  dispatch_queue_create("com.effectiveobjectivec.queueB", NULL);

dispatch_sync(queueA, ^{
    dispatch_sync(queueB, ^{
        dispatch_sync(queueA, ^{
            // Deadlock
        });
    });
});

This will always deadlock at the inner dispatch onto _queueA because it will wait for the outer dispatch_sync to finish, which itself won’t finish until the inner dispatch_sync finishes: hence deadlock. Now consider putting in the same check using dispatch_get_current_queue:

Click here to view code image

dispatch_sync(queueA, ^{
    dispatch_sync(queueB, ^{
        dispatch_block_t block = ^{ /* ... */ };
        if (dispatch_get_current_queue() == queueA) {
            block();
        } else {
            dispatch_sync(queueA, block);
        }
    });
});

However, this too will deadlock, since dispatch_get_current_queue returns the current queue, which in the preceding example will be _queueB. So the synchronous dispatch onto _queueA will still be done, resulting in deadlock, just as before.

In this scenario, the correct solution is that the accessor does not need to be made reentrant. Rather, you should ensure that the queue used for synchronization never tries to access the property; never call someString. The queue should be used only for synchronization of the property. Dispatch queues are fairly lightweight, so it’s fine to create multiple queues to ensure that the synchronization queue is used solely for synchronization of that one property.

The preceding example may seem slightly contrived, but another thing to be aware of with queues can make this problem occur when you didn’t think it would. Queues are arranged into a hierarchy, meaning that blocks enqueued on one queue are executed within their parent queue. The final queue in a hierarchy is always one of the global concurrent queues. To illustrate a simple hierarchy, see Figure 6.4.

Figure 6.4 Dispatch queue hierarchy

Blocks enqueued on either queue B or queue C are subsequently scheduled to run on serial A. So blocks queued on queues A, B, and C will be executed exclusively with respect to one another. However, blocks enqueued on queue D will run concurrently with those enqueued on queue A (and therefore B and C) because the target queue of A and D is a concurrent one. Concurrent queues execute blocks in parallel on multiple threads, if necessary, depending on system resources, such as the number of cores the CPU has.

Because of queue hierarchies, the equality check of the current queue with the queue about to be dispatched synchronously may not always work. A block enqueued on queue C, for instance, will return queue C for the current queue, so it may think it can safely dispatch synchronously onto queue A. In fact, this would result in a deadlock as before.

This problem may occur if an API allows you to specify what queue to schedule callback blocks on, but a serial synchronization queue is used internally, with its target set to the callback queue. Code in the consumer of such an API would be incorrect to assume that the current queue, as returned by dispatch_get_current_queue in callback blocks, will always equal the queue it gave. In fact, the internal synchronization queue would be returned instead.

To solve this problem, the best approach is to use the queue-specific data functions of GCD, which allow you to associate arbitrary data with a queue as a key-value pair. Most important, if no data is associated for a certain key when retrieving data, the system walks up the hierarchy until it either finds data or the root is reached. It may not be obvious how this can be used, so consider this example:

Click here to view code image

dispatch_queue_t queueA =
  dispatch_queue_create("com.effectiveobjectivec.queueA", NULL);
dispatch_queue_t queueB =
  dispatch_queue_create("com.effectiveobjectivec.queueB", NULL);
dispatch_set_target_queue(queueB, queueA);

static int kQueueSpecific;
CFStringRef queueSpecificValue = CFSTR("queueA");
dispatch_queue_set_specific(queueA,
                            &kQueueSpecific,
                            (void*)queueSpecificValue,
                            (dispatch_function_t)CFRelease);

dispatch_sync(queueB, ^{
    dispatch_block_t block = ^{ NSLog(@"No deadlock!"); };

    CFStringRef retrievedValue =
                    dispatch_get_specific(&kQueueSpecific);
    if (retrievedValue) {
        block();
    } else {
        dispatch_sync(queueA, block);
    }
});

In this example, two queues are created. The target queue of queue B is set to queue A, whose target queue stays as the default priority global concurrent queue. Then a queue-specific value is set on queue A, using the following function:

Click here to view code image

void dispatch_queue_set_specific(dispatch_queue_t queue,
                                 const void *key,
                                 void *context,
                                 dispatch_function_t destructor);

This takes the target queue to set the data on, followed by the key and the value. Both the key and the value are opaque void pointers. For the keys, the important thing to remember is that they are compared by the pointer value, not by the contents. So queue-specific data behaves differently from NSDictionary objects, which compare object equality of keys. Queue-specific data behaves more like associated references (see Item 10). Values (called context in the function prototype) are also opaque void pointers. So they can be absolutely anything you want. However, you have to perform any memory management you want on the object. This makes it very difficult to use Objective-C objects as the value under ARC. In the example, a CoreFoundation string is used as the value because ARC does not take care of memory management of any CoreFoundation object. Such objects therefore make for good queue-specific data because they can be toll-free bridged to their Objective-C Foundation classes as required.

The final argument to the function is the destructor function, which is run whenever the object held for a given key is removed either because the queue is deallocated or a new value is set for that key. The dispatch_function_t type is defined like so:

typedef void (*dispatch_function_t)(void*)

The destructor must therefore be a function that takes a single pointer as its only argument and returns void. In the example, CFRelease is given, which is an example of such a function, although it could also have been a user-defined function that in turn called CFRelease to clean up the value and perform any other necessary cleanup.

Queue-specific data therefore provides a simple-to-use mechanism to get around one of the common pitfalls of dispatch_get_current_queue. Other common uses of dispatch_get_current_queue might include debugging. In these circumstances, it is safe to use the deprecated method so long as that code is not compiled into release builds. If a specific requirement for accessing the current queue is not covered by other functions, it is best to file a feature request with Apple.

Things to Remember

The dispatch_get_current_queue function does not in general perform how you would expect. It has been deprecated and should now be used only for debugging.

Dispatch queues are organized into a hierarchy; therefore, the current queue cannot be described simply by a single queue object.

Queue-specific data can be used to solve the usual reason for using dispatch_get_current_queue, which is to avoid deadlocks owing to nonreentrant code.