7. The System Frameworks

Although it is possible to use Objective-C without using any of the system frameworks, doing so is extremely uncommon. Even the standard root class, NSObject, is part of the Foundation framework rather than part of the language itself. If you didn’t want to use Foundation, you would have to write your own root class, as well as your own collections, event loops, and other useful classes. Furthermore, you cannot use Objective-C for developing Mac OS X and iOS applications without using the system frameworks. They are powerful but have come through years of development to where they are today. Therefore, you may find some parts that feel old and are awkward to work with, but you may also find hidden gems.

Item 47: Familiarize Yourself with the System Frameworks

When writing an application in Objective-C, you will almost certainly use the system frameworks, which provide many of the common classes, such as collections, that you need to be able to write applications. If you don’t understand what the system frameworks provide, you may end up writing something that has already been written. When they upgrade their operating systems, users of your application obtain the latest versions of the system frameworks. So if you use classes from these frameworks, you benefit from any improvements made to them, without having to update your application.

A framework is a set of code packaged as a dynamic library along with header files describing its interface. Sometimes, a third-party framework built for iOS uses a static library, since iOS applications are not allowed to ship dynamic libraries with them. These are not true frameworks but are often referred to as such. However, all system frameworks use dynamic libraries on iOS still.

If you’re developing a graphical application for Mac OS X or iOS, you will come across the framework called Cocoa, which is also referred to as Cocoa Touch for iOS. Cocoa is not a framework in itself but rather a collection of other frameworks commonly used when creating applications.

The main framework you will come across is called Foundation, where classes such as NSObject, NSArray, and NSDictionary are found. The class prefix used throughout the Foundation framework is NS, which was first formulated when Objective-C was being used for work on the NeXTSTEP operating system. The Foundation framework truly is the foundation of all Objective-C applications; without it, most of this book would be irrelevant.

Foundation provides not only core features that you would expect, such as collections, but also complex features, such as string processing. For example, NSLinguisticTagger provides the ability to parse a string and find all the nouns, verbs, pronouns, and so on. In short, Foundation goes far beyond the basics.

Alongside Foundation is another framework: CoreFoundation. Although not technically Objective-C, CoreFoundation is another important framework to be familiar with when writing Objective-C applications and is a C API that mirrors much of the functionality of the Foundation framework. The CoreFoundation and Foundation frameworks are closely linked in more than name. A feature known as toll-free bridging allows seamless casting from the C data structures of CoreFoundation to the Objective-C objects of Foundation, and vice versa. For example, a string from Foundation is an NSString, which can be cast to its equivalent in CoreFoundation: CFString. Toll-free bridging works through some rather intricate code that makes CoreFoundation objects appear to the runtime as though they are Objective-C objects. Unfortunately, toll-free bridging is very complex, so replicating it yourself in your own code is tricky. This feature should be used, but copied only if you really know what you’re doing.

Along with Foundation and CoreFoundation are many other system libraries. They include but are not limited to the following:

CFNetwork This provides C-level networking facilities for talking to networks through an easy-to-use abstraction over BSD sockets. Foundation wraps parts of this framework to provide an Objective-C interface for networking, such as NSURLConnection for downloading data from a URL.

CoreAudio This provides a C-level API for interfacing with audio hardware on a device. This is one of the harder frameworks to work with, owing to the complex nature of audio processing. Fortunately, Objective-C abstractions can be used make audio processing easier.

AVFoundation This provides Objective-C objects for dealing with audio and video playback and recording, such as UI view classes for presenting video.

CoreData This provides Objective-C interfaces for persisting objects to a database. CoreData handles data fetching and saving and can be used cross-platform between Mac OS X and iOS.

CoreText This provides a C interface for high-performance text typesetting and rendering.

Other frameworks are available, but looking at the few listed here highlights an important feature of programming in Objective-C: Often, you will need to drop down to use C-level APIs. APIs written in C benefit from the speed improvement of bypassing the Objective-C runtime. Of course, more care needs to be taken with memory management in those APIs, since ARC (see Item 30) is available only to Objective-C objects. Being familiar with the basics of C is important if you need to use one of these frameworks.

You will likely be writing Mac OS X or iOS applications that make use of the UI frameworks. The core UI frameworks, called AppKit and UIKit, respectively, both provide Objective-C classes built on top of Foundation and CoreFoundation. They provide UI elements and the glue to put everything together to create an application. Underneath these main UI frameworks are the CoreAnimation and CoreGraphics frameworks.

CoreAnimation is written in Objective-C and provides the tools that the UI frameworks use to render graphics and perform animations. You may never need to drop down to this level, but it is good to know that it is there. CoreAnimation is not a framework on its own but rather is part of the QuartzCore framework. However, CoreAnimation should still be considered as a first-class citizen.

CoreGraphics is written in C and provides data structures and functions that are essential for 2D rendering. For example, this is where the CGPoint, CGSize, and CGRect data structures are defined, and all are used by the UIKit class UIView to indicate where views should be positioned relative to one another.

Many other frameworks are built on top of the UI frameworks, such as MapKit, which provides mapping functionality to iOS, or the Social framework, which provides social networking facilities to both Mac OS X and iOS. You will usually work with these frameworks and the core UI framework for the platform on which you are working.

Overall, many frameworks come as standard with Mac OS X and iOS installations. So, if you need to write a new utility class, for example, consider searching for it first in the system frameworks. Often, it will have already been written for you.

Things to Remember

Many system frameworks are available to you. The most important ones, Foundation and CoreFoundation, provide the core functionality on which much of an application is built.

Frameworks exist for many common tasks, such as audio and video processing, networking, and data managing.

Remember that frameworks written in pure C rather than Objective-C are just as important to you, so to be a good Objective-C developer, you should understand the core concepts of C.

Item 48: Prefer Block Enumeration to for Loops

Enumerating a collection is a very common task in programming, and modern Objective-C has many ways to do so, ranging from standard C loops to NSEnumerator in Objective-C 1.0 and fast enumeration in Objective-C 2.0. The addition of blocks (see Item 37) to the language brought a few new methods that developers sometimes overlooked. These methods allow you to enumerate a collection by passing a block that should be run for each item in the collection and are usually much easier to use, as I will explain.

The collections presented in this item—NSArray, NSDictionary, and NSSet—are the ones most commonly used. Additionally, custom collections can all be made to support any of the enumeration techniques outlined, although explaining how is beyond the scope of this item.

For Loops

The first method for enumerating a collection is the good, old-fashioned for loop, which harks back to Objective-C’s roots in the C language. This method is very basic and therefore quite limiting. The usual idea is to do something like this:

Click here to view code image

NSArray *anArray = /* ... */;
for (int i = 0; i < anArray.count; i++) {
    id object = anArray[i];
    // Do something with 'object'
}

This is acceptable but becomes more complicated for a dictionary or a set:

Click here to view code image

// Dictionary
NSDictionary *aDictionary = /* ... */;
NSArray *keys = [aDictionary allKeys];
for (int i = 0; i < keys.count; i++) {
    id key = keys[i];
    id value = aDictionary[key];
    // Do something with 'key' and 'value'
}

// Set
NSSet *aSet = /* ... */;
NSArray *objects = [aSet allObjects];
for (int i = 0; i < objects.count; i++) {
    id object = objects[i];
    // Do something with 'object'
}

By definition, dictionaries and sets are unordered, so there’s no way to directly access the value at a certain integer index. Therefore, you need to ask for all the keys for the dictionary or all the objects for a set; in both cases, the ordered array returned can then be enumerated instead to access the values. Creating this extra array is extra work and causes an extra object to be created that retains the objects in the collection. Of course, those objects will be released when the array is released, but it’s more unnecessary method calls. All the other enumeration techniques mitigate needing to create an extra intermediate array.

Enumerating backward can be achieved with a for loop by starting at the count of objects minus one, decrementing the counter on each iteration, and stopping when the counter equals zero. This is much easier.

Objective-C 1.0 Enumeration Using NSEnumerator

The NSEnumerator object is an abstract base class that defines only two methods for concrete subclasses to implement:

- (NSArray*)allObjects
- (id)nextObject

The key method is nextObject, which returns the next object in the enumeration. Each time the method is invoked, internal data structures are updated such that the next invocation returns the next object. After all the objects in the enumeration have been returned, nil is returned, signaling the end of enumeration.

All the built-in collection classes within the Foundation framework implement enumeration in this way. For example, enumerating an array is done like this:

Click here to view code image

NSArray *anArray = /* ... */;
NSEnumerator *enumerator = [anArray objectEnumerator];
id object;
while ((object = [enumerator nextObject]) != nil) {
    // Do something with 'object'
}

This is similar to a standard for loop but is more work. The only real benefit is that enumerating any collection is made with similar syntax. For example, consider the equivalent for a dictionary and a set:

Click here to view code image

// Dictionary
NSDictionary *aDictionary = /* ... */;
NSEnumerator *enumerator = [aDictionary keyEnumerator];
id key;
while ((key = [enumerator nextObject]) != nil) {
    id value = aDictionary[key];
    // Do something with 'key' and 'value'
}

// Set
NSSet *aSet = /* ... */;
NSEnumerator *enumerator = [aSet objectEnumerator];
id object;
while ((object = [enumerator nextObject]) != nil) {
    // Do something with 'object'
}

The dictionary enumeration is slightly different because a dictionary has keys and values, so the value has to be pulled out of the dictionary given the key. The additional benefit to NSEnumerator is that different types of enumerators are often available. For example, with an array, there is a reverse enumerator; if that is used instead, the collection is iterated in reverse. For example:

Click here to view code image

NSArray *anArray = /* ... */;
NSEnumerator *enumerator = [anArray reverseObjectEnumerator];
id object;
while ((object = [enumerator nextObject]) != nil) {
    // Do something with 'object'
}

This is much easier to read than the equivalent syntax of reverse enumerating using a for loop.

Fast Enumeration

Fast enumeration was introduced with Objective-C 2.0. Fast enumeration is similar to enumeration using NSEnumerator, except that the syntax is much more condensed, adding a keyword, in, to the for-loop syntax. This keyword greatly condenses the syntax for enumerating a collection, such as an array:

Click here to view code image

NSArray *anArray = /* ... */;
for (id object in anArray) {
    // Do something with 'object'
}

This is much simpler! It works by using a protocol called NSFastEnumeration, to which an object can conform in order to indicate that it supports fast enumeration. The protocol defines a single method:

Click here to view code image

- (NSUInteger)countByEnumeratingWithState:
                            (NSFastEnumerationState*)state
                                  objects:(id*)stackbuffer
                                    count:(NSUInteger)length

Explaining how this works in full is beyond the scope of this item. However, decent tutorials on the Internet explain this topic well. The important thing to note is that this method allows the class to return multiple objects at the same time, which means that the enumeration loop can be more efficient.

Enumerating dictionaries and sets is just as simple:

Click here to view code image

// Dictionary
NSDictionary *aDictionary = /* ... */;
for (id key in aDictionary) {
    id value = aDictionary[key];
    // Do something with 'key' and 'value'
}

// Set
NSSet *aSet = /* ... */;
for (id object in aSet) {
    // Do something with 'object'
}

Reverse enumeration can be achieved by noting that NSEnumerator objects also implement NSFastEnumeration. So to reverse iterate through an array, you can do the following:

Click here to view code image

NSArray *anArray = /* ... */;
for (id object in [anArray reverseObjectEnumerator]) {
    // Do something with 'object'
}

This method of enumeration is the best so far in terms of syntax and efficiency, but enumerating a dictionary still requires an additional step if you want both the key and the value. Also, the index of enumeration is not easily accessible, unlike a traditional for loop. The index is often useful to have during an iteration, as many algorithms will make use of it.

Block-Based Enumeration

Block-based methods are the final type of enumeration available in modern Objective-C. The most basic method for enumerating an array is as follows, defined on NSArray:

Click here to view code image

- (void)enumerateObjectsUsingBlock:
           (void(^)(id object, NSUInteger idx, BOOL *stop))block

The other methods in this family can take options to control the enumeration and are discussed later.

For the array and the set, the block that is performed for each iteration takes the object at that iteration, the index into the iteration, and a pointer to a Boolean. The first two parameters are self-explanatory. The third provides a mechanism for halting the enumeration.

For example, you can enumerate an array with this method as follows:

Click here to view code image

NSArray *anArray = /* ... */;
[anArray enumerateObjectsUsingBlock:
    ^(id object, NSUInteger idx, BOOL *stop){
        // Do something with 'object'
        if (shouldStop) {
            *stop = YES;
        }
    }];

This syntax is slightly more verbose than fast enumeration but is clean, and you get both the index of iteration and the object. This method also provides a clean way to stop the enumeration, if you wish, through the stop variable, although a break can achieve the same thing in the other methods of enumeration and is just as clean.

It’s not just arrays that can be enumerated in this way. The same block-enumeration method exists in NSSet and a slightly different one in NSDictionary:

Click here to view code image

- (void)enumerateKeysAndObjectsUsingBlock:
                    (void(^)(id key, id object, BOOL *stop))block

Therefore, enumerating dictionaries and sets is just as simple:

Click here to view code image

// Dictionary
NSDictionary *aDictionary = /* ... */;
[aDictionary enumerateKeysAndObjectsUsingBlock:
    ^(id key, id object, BOOL *stop){
        // Do something with 'key' and 'object'
        if (shouldStop) {
            *stop = YES;
        }
    }];

// Set
NSSet *aSet = /* ... */;
[aSet enumerateObjectsUsingBlock:
    ^(id object, BOOL *stop){
        // Do something with 'object'
        if (shouldStop) {
            *stop = YES;
        }
    }];

The big win here is that you get a lot more information directly in the block. In the case of arrays, you get the index of enumeration. The same goes for ordered sets (NSOrderedSet). In the case of a dictionary, you get both the key and the value without any additional work, thereby saving the extra cycles required to obtain the value for a given key. Instead, the dictionary can give both at the same time, which is highly likely to be far more efficient, since keys and values will be stored together in a dictionary’s internal data structures.

Another benefit is that you can change the method signature of the block to limit the need for casting; in effect, you push the cast into the block-method signature. Consider the code for enumerating a dictionary with fast enumeration. If the objects in the dictionary are known to you as strings, you may do this:

Click here to view code image

for (NSString *key in aDictionary) {
    NSString *object = (NSString*)aDictionary[key];
    // Do something with 'key' and 'object'
}

With the block-based method, you can do the cast in the block-method signature like so:

Click here to view code image

NSDictionary *aDictionary = /* ... */;
[aDictionary enumerateKeysAndObjectsUsingBlock:
    ^(NSString *key, NSString *obj, BOOL *stop){
        // Do something with 'key' and 'obj'
    }];

This works because the id type is rather special and can be overridden like this. If the original block signature had defined key and object as NSObject*, you wouldn’t be able to do this trick. This technique is more useful than it seems at first glance. Giving the exact type of an object allows the compiler to help you by throwing an error if a method you call on the object doesn’t exist. If you can guarantee what type of objects are in a certain collection, indicating the type in this way should always be done.

The ability to reverse enumerate is not lost. Arrays, dictionaries, and sets all implement a variant of the preceding method, allowing you to pass an options mask:

Click here to view code image

- (void)enumerateObjectsWithOptions:
              (NSEnumerationOptions)options
                         usingBlock:
              (void(^)(id obj, NSUInteger idx, BOOL *stop))block
- (void)enumerateKeysAndObjectsWithOptions:
              (NSEnumerationOptions)options
                                usingBlock:
              (void(^)(id key, id obj, BOOL *stop))block

The NSEnumerationOptions type is an enum whose values you can bitwise OR together to indicate how the enumeration should behave. For example, you can request that iteration be concurrent, meaning that the blocks for each iteration will be executed in parallel if that is possible with current system resources. This is achieved through the NSEnumerationConcurrent option. Underneath, this option uses GCD to handle concurrent execution, most likely making use of dispatch groups (see Item 44). However, the implementation is not relevant here. Asking for reverse iteration is achieved through the NSEnumerationReverse option. Note that this is available only for situations in which it makes sense, such as arrays or ordered sets.

Overall, block enumeration has all the benefits of the other methods combined, and more. It is slightly more verbose than fast enumeration. But the benefits of having the index of enumeration, both the key and the value in dictionary enumeration, and the option to perform iterations concurrently are worth the extra source code.

Things to Remember

Enumerating collections can be achieved in four ways. The for loop is the most basic, followed by enumeration using NSEnumerator and fast enumeration. The most modern and advanced way is using the block-enumeration methods.

Block enumeration allows you to perform the enumeration concurrently, without any additional code, by making use of GCD. This cannot as easily be achieved with the other enumeration techniques.

Alter the block signature to indicate the precise types of objects if you know them.

Item 49: Use Toll-Free Bridging for Collections with Custom Memory-Management Semantics

The collection classes that come with the Objective-C system libraries are fairly extensive: arrays, dictionaries, and sets. The Foundation framework defines Objective-C classes for these and other types of collections. Similarly, the CoreFoundation framework defines C APIs for manipulating data structures that represent these and other types of collections. For example, NSArray is Foundation’s Objective-C class for an array, and CFArray is CoreFoundation’s equivalent. These two ways of creating an array may seem distinct, but a powerful feature called toll-free bridging allows you to cast between the two classes seamlessly.

Toll-free bridging allows you to cast between Objective-C classes defined in Foundation and C data structures defined in CoreFoundation and vice versa, of course. I refer to the C-level APIs as data structures rather than classes or objects because they are not the same as classes or objects from Objective-C. For example, CFArray is referenced by a CFArrayRef, which is a pointer to a struct __CFArray. This struct is manipulated by using such functions as CFArrayGetCount to obtain the size of the array. This is distinct from its Objective-C counterpart, where you create an NSArray object and call methods, such as count, on that object to obtain the size of the array.

A simple toll-free bridging example is as follows:

Click here to view code image

NSArray *anNSArray = @[@1, @2, @3, @4, @5];
CFArrayRef aCFArray = (__bridge CFArrayRef)anNSArray;
NSLog(@"Size of array = %li", CFArrayGetCount(aCFArray));
// Output: Size of array = 5

The __bridge within the cast tells ARC (see Item 30) what to do with the Objective-C object that forms part of the cast. A __bridge on its own means that ARC still has ownership of the Objective-C object. A __bridge_retained, conversely, means that ARC will hand over ownership of the object. If this were used in the preceding example, we would be responsible for adding in a CFRelease(aCFArray) after the array had finished with it. Similarly, the opposite is done with __bridge_transfer. For example if a CFArrayRef is being cast to an NSArray* and you want ARC to take ownership of the object, you use this type of cast. These three types of casting are known as bridged casts.

But, you may be wondering, why you would ever want to use this feature in a purely Objective-C application? Well, Foundation’s Objective-C classes can do some things that CoreFoundation’s C data structures cannot, and vice versa. One major problem that crops up with Foundation’s dictionary, for example, is that keys are copied and values are retained. These semantics cannot be altered unless you use the power of toll-free bridging.

The CoreFoundation dictionary type is called CFDictionary. The mutable counterpart is called CFMutableDictionary. When creating a CFMutableDictionary, you can specify custom memory-management semantics to apply to both keys and values by using the following method:

Click here to view code image

CFMutableDictionaryRef CFDictionaryCreateMutable(
    CFAllocatorRef allocator,
    CFIndex capacity,
    const CFDictionaryKeyCallBacks *keyCallBacks,
    const CFDictionaryValueCallBacks *valueCallBacks
)

The first parameter defines the allocator to use. This part of Core-Foundation is slightly alien if you have spent most of your time in Objective-C land. An allocator is responsible for allocating and deallocating the memory required to hold the data structures for CoreFoundation objects. Usually, you would pass NULL here to use the default allocator.

The second parameter simply defines how big to make the dictionary initially. This doesn’t put a cap on the maximum size but rather is a hint to the allocator about how much memory to allocate to start. If you know that you’re going to create a dictionary with ten objects, you would pass 10.

The final parameters are the interesting ones. They define the callbacks that will be run when various things happen to the keys and values stored in the dictionary. These parameters are both pointers to structures, which look like this:

Click here to view code image

struct CFDictionaryKeyCallBacks {
    CFIndex version;
    CFDictionaryRetainCallBack retain;
    CFDictionaryReleaseCallBack release;
    CFDictionaryCopyDescriptionCallBack copyDescription;
    CFDictionaryEqualCallBack equal;
    CFDictionaryHashCallBack hash;
};

struct CFDictionaryValueCallBacks {
    CFIndex version;
    CFDictionaryRetainCallBack retain;
    CFDictionaryReleaseCallBack release;
    CFDictionaryCopyDescriptionCallBack copyDescription;
    CFDictionaryEqualCallBack equal;
};

The version parameter should be set to 0 at present. This has always been the case, but the value is there in case Apple decides to change the structure. This parameter can be used to check compatibility between newer and older versions. The rest of the structures are all function pointers, defining which functions should be run when each of the tasks needs to be done. For example, the retain function is called on each key and value added to the dictionary. The type of this parameter is as follows:

Click here to view code image

typedef const void* (*CFDictionaryRetainCallBack) (
    CFAllocatorRef allocator,
    const void *value
);

So it is a pointer to a function that takes a CFAllocatorRef and a const void*. The value passed in to the function is the key or the value that wants to be added to the dictionary. A void* is returned, which is the value that ends up being put into the dictionary. You could write your own callback as follows:

Click here to view code image

const void* CustomCallback(CFAllocatorRef allocator,
                           const void *value)
{
    return value;
}

This simply returns the value unaltered. So in this case, if a dictionary were created with this function for the retain callback, keys and values would not be retained. By coupling this with toll-free bridging, you can create an NSDictionary object that behaves differently from one created simply in Objective-C.

A full example of how this can be effective is as follows:

Click here to view code image

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

const void* EOCRetainCallback(CFAllocatorRef allocator,
                              const void *value)
{
    return CFRetain(value);
}

void EOCReleaseCallback(CFAllocatorRef allocator,
                        const void *value)
{
    CFRelease(value);
}

CFDictionaryKeyCallBacks keyCallbacks = {
    0,
    EOCRetainCallback,
    EOCReleaseCallback,
    NULL,
    CFEqual,
    CFHash
};

CFDictionaryValueCallBacks valueCallbacks = {
    0,
    EOCRetainCallback,
    EOCReleaseCallback,
    NULL,
    CFEqual
};

CFMutableDictionaryRef aCFDictionary =
    CFDictionaryCreateMutable(NULL,
                              0,
                              &keyCallbacks,
                              &valueCallbacks);

NSMutableDictionary *anNSDictionary =
    (__bridge_transfer NSMutableDictionary*)aCFDictionary;

In the callbacks, NULL is specified for the copyDescription callback because the default is fine. The equal and hash callbacks are set to CFEqual and CFHash, respectively, because they use the same method as the default NSMutableDictionary implementation. CFEqual will end up calling NSObject’s isEqual: method, and CFHash will end up calling NSObject’s hash method. This is yet more power of toll-free bridging.

The retain and release callbacks of both the keys and the values are set to the EOCRetainCallback and EOCReleaseCallback functions, respectively. But what use is that? Recall that NSMutableDictionary copies its keys and retains its values by default. What if the objects you want to use as keys cannot be copied? In that case, you cannot use them in a normal NSMutableDictionary, because doing so will result in a runtime error like this:

Click here to view code image

*** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[EOCClass
copyWithZone:]: unrecognized selector sent to instance
0x7fd069c080b0'

That error means that the class does not support the NSCopying protocol, because copyWithZone: is not implemented. By dropping down to the CoreFoundation level and creating the dictionary there, you can alter the memory-management semantics and create a dictionary that retains rather than copies the keys.

A similar approach could be used to create an array or a set that doesn’t retain the objects it holds. This might be useful if, by having an array that retains certain objects, you introduce a retain cycle. Note, however, that this scenario could possibly be solved better in another way. Creating an array that doesn’t retain its objects is fraught with danger. If one of the objects happens to be deallocated but is still in the array, the application will likely crash if that object is accessed.

Things to Remember

Toll-free bridging allows you to cast between Foundation’s Objective-C objects and CoreFoundation’s C data structures.

Dropping down to CoreFoundation to create a collection allows you to specify various callbacks that are used when the collection handles its contents. Casting this through toll-free bridging allows you to end up with an Objective-C collection that has custom memory-management semantics.

Item 50: Use NSCache Instead of NSDictionary for Caches

A common problem encountered when developing a Mac OS X or an iOS application that downloads images from the Internet is deciding what to do about caching them. A good first approach is to use a dictionary to store in memory images that have been downloaded, such that they don’t need to be downloaded again if they are requested later. A naïve developer will simply use an NSDictionary (or rather a mutable one) because that’s a commonly used class. However, an even better class, called NSCache, is also part of the Foundation framework and has been designed exactly for this task.

The benefit of NSCache over an NSDictionary is that as system memory becomes full, the cache is automatically pruned. When using a dictionary, you often end up having to write pruning code yourself by hooking into system notifications for low memory. However, NSCache offers this automatically; because it is part of the Foundation framework, it will be able to hook in deeper to the system than you could yourself. An NSCache will also prune the least recently used objects first. Writing the code to support this yourself with a dictionary would be quite complex.

Also, an NSCache does not copy keys but rather retains them. This is something that can be controlled on NSDictionary but requires more complex code (see Item 49). A cache usually would rather not copy the keys because often, the key will be an object that does not support copying. Since NSCache doesn’t copy by default, it makes it an easier class to work with in these situations. Also, NSCache is thread safe. This is certainly not true of an NSDictionary, which means that you can poke away at an NSCache from multiple threads at the same time without having to introduce any locks of your own. This is usually useful for a cache because you may want to read from it in one thread, and, if a certain key doesn’t exist, you may download the data for that key. The callbacks for downloading may be in a background thread, so you end up adding to the cache in this other thread.

You can control when a cache will prune its contents. Two user-controllable metrics alongside the system resources are a limit on both the number of objects in the cache and the overall “cost” of the objects. Each object can optionally be given a cost when added to the cache. When the total number of objects exceeds the count limit or the total cost exceeds the cost limit, the cache may evict objects, just as it does when the available system memory becomes tight. However, it is important to note that it may evict rather than it will evict. The order in which objects are evicted is implementation specific. In particular, this means that manipulating the cost metric in order to force eviction in a certain order is a bad idea.

The cost metric should be used only when adding an object to the cache if calculating the cost is very cheap. If calculating it is expensive, you may find that using the cache becomes suboptimal, since you are having to calculate this additional factor each time an object is cached. After all, caches are meant to help with making an application more responsive. For example, having to go to the disk to find the size of a file or to a database to determine the cost would be bad ideas. However, an example of a good cost to use is if NSData objects are added to the cache; in that case, you can use the size of that data as the cost. This is already known to the NSData object, and so calculating it is as simple as reading a property.

The following is an example of using a cache:

Click here to view code image

#import <Foundation/Foundation.h>

// Network fetcher class
typedef void(^EOCNetworkFetcherCompletionHandler)(NSData *data);
@interface EOCNetworkFetcher : NSObject
- (id)initWithURL:(NSURL*)url;
- (void)startWithCompletionHandler:
                 (EOCNetworkFetcherCompletionHandler)handler;
@end

// Class that uses the network fetcher and caches results
@interface EOCClass : NSObject
@end

@implementation EOCClass {
    NSCache *_cache;
}

- (id)init {
    if ((self = [super init])) {
        _cache = [NSCache new];

        // Cache a maximum of 100 URLs
        _cache.countLimit = 100;

        /**
         * The size in bytes of data is used as the cost,
         * so this sets a cost limit of 5MB.
         */
        _cache.totalCostLimit = 5 * 1024 * 1024;
    }
    return self;
}

- (void)downloadDataForURL:(NSURL*)url {
    NSData *cachedData = [_cache objectForKey:url];
    if (cachedData) {
        // Cache hit
        [self useData:cachedData];
    } else {
        // Cache miss
        EOCNetworkFetcher *fetcher =
            [[EOCNetworkFetcher alloc] initWithURL:url];
        [fetcher startWithCompletionHandler:^(NSData *data){
            [_cache setObject:data forKey:url cost:data.length];
            [self useData:data];
        }];
    }
}

@end

In this example, the URL to be retrieved is used as the cache key. When there is a cache miss, the data is downloaded and added to the cache. The cost is calculated as the data’s length. When the cache is created, the total number of objects that can be cached is set to 100, and the overall cost is set to a value that equates to 5MB because the unit of cost is the size in bytes.

Another class that can be used effectively alongside NSCache is called NSPurgeableData, an NSMutableData subclass that implements a protocol called NSDiscardableContent. This protocol defines an interface for objects whose memory can be discarded, if required. This means that the memory backing NSPurgeableData is freed when system resources are getting low. The method called isContentDiscarded, part of the NSDiscardableContent protocol, returns whether the memory has been freed.

If a purgeable data object needs to be accessed, you call beginContentAccess to tell it that it should not be discarded now. When you are done with it, you call endContentAccess to tell it that it is free to be discarded, if desired. These calls can be nested, so you can think of them as just like a reference count being incremented and decremented. Only when the reference count is zero can the object be discarded.

If NSPurgeableData objects are added to an NSCache, a purgeable data object that is purged is automatically removed from the cache. This can optionally be turned on or off through the cache’s evictsObjectsWithDiscardedContent property.

The preceding example could therefore be changed to make use of purgeable data, like so:

Click here to view code image

- (void)downloadDataForURL:(NSURL*)url {
    NSPurgeableData *cachedData = [_cache objectForKey:url];
    if (cachedData) {
        // Stop the data being purged
        [cacheData beginContentAccess];

        // Use the cached data
        [self useData:cachedData];

        // Mark that the data may be purged again
        [cacheData endContentAccess];
    } else {
        // Cache miss
        EOCNetworkFetcher *fetcher =
            [[EOCNetworkFetcher alloc] initWithURL:url];
        [fetcher startWithCompletionHandler:^(NSData *data){
            NSPurgeableData *purgeableData =
                [NSPurgeableData dataWithData:data];
            [_cache setObject:purgeableData
                       forKey:url
                         cost:purgeableData.length];

            // Don't need to beginContentAccess as it begins
            // with access already marked

            // Use the retrieved data
            [self useData:data];

            // Mark that the data may be purged now
            [purgeableData endContentAccess];
        }];
    }
}

Note that when a purgeable data object is created, it is returned with a +1 purge reference count, so you do not need to specifically call beginContentAccess on it, but you must balance the +1 with a call to endContentAccess.

Things to Remember

Consider using NSCache in the place of NSDictionary objects being used as caches. Caches provide optimal pruning behavior, thread safety, and don’t copy keys, unlike a dictionary.

Use the count limit and cost limits to manipulate the metrics that define when objects are pruned from the cache. But never rely on those metrics to be hard limits; they are purely guidance for the cache.

Use NSPurgeableData objects with a cache to provide autopurging data that is also automatically removed from the cache when purged.

Caches will make your applications more responsive if used correctly. Cache only data that is expensive to recalculate, such as data that needs to be fetched from the network or read from disk.

Item 51: Keep initialize and load Implementations Lean

Sometimes, a class needs to perform some initialization before it can be used successfully. In Objective-C, objects inheriting from the NSObject root class, which is the vast majority of classes, have a couple of methods available to them to perform this task.

The first of these methods is called load, and its prototype is as follows:

+ (void)load

It is called once and only once for every class and category that is added to the runtime. This happens when the library containing the class or category is loaded, generally at application launch, and is certainly the case for any code written for iOS. Mac OS X applications are generally freer to use features such as dynamic loading, and it’s therefore possible that a library will be loaded after application launch. The load method for a category is always called after the class that the category is on.

The problem with the load method is that the runtime is in a fragile state at the time it is run. All superclasses’ load methods are guaranteed to be run before those of any class; also, any load methods from classes in dependent libraries are guaranteed to be run first. Within any given library, however, you cannot assume the order in which classes are loaded. Therefore, it is unsafe to use another class in a load method. For example, consider the following code:

Click here to view code image

#import <Foundation/Foundation.h>
#import "EOCClassA.h" //< From the same library

@interface EOCClassB : NSObject
@end

@implementation EOCClassB
+ (void)load {
    NSLog(@"Loading EOCClassB");
    EOCClassA *object = [EOCClassA new];
    // Use 'object'
}
@end

It is safe to use NSLog and the associated NSString that is being logged, since we know that the Foundation framework has already loaded by the time the load method is run. However, it is unsafe to use EOCClassA from EOCClassB’s load method, since you cannot know deterministically whether EOCClassA has been loaded by the time EOCClassB’s load method is invoked. For all you know, in its own load method, EOCClassA may perform some important work that must be done before an instance can be used.

An important thing to note is that load does not follow the normal inheritance rules for methods. A class that does not implement load is not called, regardless of whether any of its superclasses do. Also, load can appear in a category and the class itself. Both implementations will be called, with the class’s coming before the category’s.

You should also make sure that an implementation of load is lean, meaning that as little as possible is done, because the entire application will be blocked while loading is taking place. If a load method does some heavy lifting, the application will be unresponsive for that period. You should not attempt to wait on any locks or call methods that may themselves call locks. In essence, you should do very little. In fact, load is almost never the right solution to perform tasks that have to happen before a class is used. Its only real use is for debugging, perhaps when used in a category if you want to check that the category has been successfully loaded. Perhaps the method was of use historically, but it’s safe to say that any modern Objective-C code base does not need to be concerned with it.

The other way to perform class initialization is by overriding the following method:

+ (void)initialize

This method is called on every class, once and only once, before the class is used. The method is called by the runtime and should never be invoked directly. It is similar to load but subtly different in a few important ways. First, it is called lazily, meaning that it is called only before the class is used for the first time. Thus, a certain class’s initialize method will never be run if the class is never used. However, this does mean that there is no period when all initialize implementations are run, unlike load, which blocks the application until all have finished.

The second difference from load is that the runtime is in a normal state during execution and therefore it is safe to use and call any method on any class from a runtime integrity point of view. Also, the runtime ensures that initialize is executed in a thread-safe environment, meaning that only the thread executing initialize is allowed to interact with the class or instances of the class. Other threads will block until initialize is completed.

The final difference is that initialize is sent just like any other message; if a class doesn’t implement it but its superclass does, that implementation will be run. This might sound obvious, but it is often overlooked. Consider the following two classes:

Click here to view code image

#import <Foundation/Foundation.h>

@interface EOCBaseClass : NSObject
@end

@implementation EOCBaseClass
+ (void)initialize {
    NSLog(@"%@ initialize", self);
}
@end

@interface EOCSubClass : EOCBaseClass
@end

@implementation EOCSubClass
@end

Even though it does not implement initialize, EOCSubClass will still be sent the message. All superclasses’ initialize implementations are called first as well. So the first time EOCSubClass is used, you would see the following output:

EOCBaseClass initialize
EOCSubClass initialize

That may surprise you, but it makes perfect sense. Normal inheritance rules apply to initialize just like other methods (apart from load!), so the implementation from EOCBaseClass is run once when EOCBaseClass is initialized and again when EOCSubClass is initialized, since EOCSubClass does not override it. This is why it is common to see initialize implementations look like this:

Click here to view code image

+ (void)initialize {
    if (self == [EOCBaseClass class]) {
        NSLog(@"%@ initialized", self);
    }
}

With this check in place, it is only when the desired class is initialized that the initialization work is done. If this is applied to the earlier example, instead of two log lines being printed, only one is:

EOCBaseClass initialize

All this leads on to the main point about both load and initialize as hinted at earlier. Implementations of both should be lean. They should be limited to setting up state that is required for the class to operate correctly but not do any work that may take a long time or take out locks. In the case of load, the reasons are as covered earlier; the reasons for keeping initialize lean are similar. First, nobody wants an application that hangs. A class will be initialized the first time it is used and this can be from any thread. If this happens to be the UI thread, that will block while the initialization is taking place, causing an unresponsive application. It’s sometimes hard to predict which thread will first use a class, and it’s certainly not ideal to attempt to force a certain thread to be the one that causes a class to be initialized.

Second, you do not control when a class will be initialized. It is guaranteed to be before a class is used for the first time, but relying on its being at any given time is dangerous. The runtime may be updated in future to subtly change the way in which classes are initialized, and your assumptions about exactly when a class is initialized may become invalid.

Finally, if you make implementations complex, you may start using, either directly or indirectly, other classes from your class. If these classes have not yet been initialized, they will be forced to initialize as well. However, the first class’s initializer won’t have finished running. If the other class relies on certain data in the first class being initialized, that data may not have been initialized yet by the time the other class’s initialize runs. For example:

Click here to view code image

#import <Foundation/Foundation.h>

static id EOCClassAInternalData;
@interface EOCClassA : NSObject
@end

static id EOCClassBInternalData;
@interface EOCClassB : NSObject
@end

@implementation EOCClassA

+ (void)initialize {
    if (self == [EOCClassA class]) {
        [EOCClassB doSomethingThatUsesItsInternalData];
        EOCClassAInternalData = [self setupInternalData];
    }
}

@end

@implementation EOCClassB

+ (void)initialize {
    if (self == [EOCClassB class]) {
        [EOCClassA doSomethingThatUsesItsInternalData];
        EOCClassBInternalData = [self setupInternalData];
    }
}

@end

If EOCClassA is initialized first, it has not set up its internal data by the time EOCClassB calls doSomethingThatUsesItsInternalData on EOCClassA. In reality, the problem will not be as apparent as it is here and may involve more than two classes. It may therefore be harder to track down why something isn’t working properly.

So the purpose of initialize is for setting up internal data. You should try not to call any methods, even those on the class itself. If you do and later down the line end up adding functionality to the method it calls, you may end up with the problems described. Keep the initializer for setting up global state that cannot be initialized at compile time. The following example illustrates this:

Click here to view code image

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

@interface EOCClass : NSObject
@end

// EOCClass.m
#import "EOCClass.h"

static const int kInterval = 10;
static NSMutableArray *kSomeObjects;

@implementation EOCClass

+ (void)initialize {
    if (self == [EOCClass class]) {
        kSomeObjects = [NSMutableArray new];
    }
}

@end

The integer can be defined at compile time, but the mutable array cannot, since it is an Objective-C object and therefore needs the runtime to be active before an instance can be created. Note that some Objective-C objects can be created at compile time, such as NSString instances. But the compiler would throw an error if you attempted the following:

static NSMutableArray *kSomeObjects = [NSMutableArray new];

Bear these thoughts in mind if you find yourself writing a load or initialize method. Keeping implementations lean can save hours of debugging. If you do find yourself wanting to do more than initialize global state, consider creating a method that performs this, and mandate that consumers call it before they use the class. Such examples would be singleton classes that perform additional work when they are first accessed.

Things to Remember

Classes go through a load phase in which they have the load method called on them if it has been implemented. This method may also be present in categories whereby the class load always happens before the category load. Unlike other methods, the load method does not participate in overriding.

Before a class is used for the first time, it is sent the initialize method. This method does participate in overriding, so it is usually best to check which class is being initialized.

Both implementations of load and initialize should be kept lean, which helps to keep applications responsive and reduces the likelihood that interdependency cycles will be introduced.

Keep initialize methods for setting up global state that cannot be done at compile time.

Item 52: Remember that NSTimer Retains Its Target

Timers are a useful object to have at your disposal. The Foundation framework contains a class called NSTimer that can be scheduled to run either at an absolute date and time or after a given delay. Timers can also repeat and therefore have an associated interval to define how frequently they should fire. You may use one to fire every 5 seconds to handle polling of a resource, for example.

Timers are associated with a run loop, and the run loop handles when it should fire. When a timer is created, it can either be prescheduled in the current run loop, or you can create it and schedule it yourself. Either way, the timer will fire only if it is scheduled in a run loop. For example, the method to create a timer that is prescheduled is as follows:

Click here to view code image

+ (NSTimer *)scheduledTimerWithTimeInterval:
                            (NSTimeInterval)seconds
                                     target:(id)target
                                   selector:(SEL)selector
                                   userInfo:(id)userInfo
                                    repeats:(BOOL)repeats

This method can be used to create a timer that fires after a certain time interval. Optionally, it can repeat until it is manually stopped at a later time. The target and the selector specify which selector should be called on which object when the timer fires. The timer retains its target and will release it when the timer is invalidated. A timer is invalidated either through a call to invalidate or when it fires. If a timer is set to repeat, you invalidate the timer when you want to stop it.

Because the timer retains its target, repeating timers can often cause problems in applications. This means that you can often get into a retain-cycle situation with repeating timers. To see why, consider this example:

Click here to view code image

#import <Foundation/Foundation.h>

@interface EOCClass : NSObject
- (void)startPolling;
- (void)stopPolling;
@end

@implementation EOCClass {
    NSTimer *_pollTimer;
}

- (id)init {
    return [super init];
}

- (void)dealloc {
    [_pollTimer invalidate];
}

- (void)stopPolling {
    [_pollTimer invalidate];
    _pollTimer = nil;
}

- (void)startPolling {
    _pollTimer =
    [NSTimer scheduledTimerWithTimeInterval:5.0
                                     target:self
                                   selector:@selector(p_doPoll)
                                   userInfo:nil
                                    repeats:YES];
}

- (void)p_doPoll {
    // Poll the resource
}

@end

Can you spot the problem here? Consider what happens if an instance of this class is created and polling is started. The timer is created, which retains the instance because the target is self. However, the timer is also retained by the instance because it is set as an instance variable. (Recall that with ARC, Item 30, this means that it is retained.) This sets up a retain cycle, which would be fine if the retain cycle were broken at some point. The only way it can be broken is if the instance variable is changed or the timer is invalidated. So the only way it is broken is if stopPolling is called or the instance is deallocated. You cannot assume that stopPolling will be called unless you control all the code that uses this class. Even then, it is not good practice to require that a method be called to avoid a leak. Also, there is a chicken-and-egg situation with the other way the timer is invalidated through deallocation. The instance will not be deallocated, because its retain count will never drop to zero while the timer is valid. And the timer will stay valid until it is invalidated. Figure 7.1 illustrates this.

Figure 7.1 Retain cycle because timer retains its target, which in turn retains the timer

Once the final reference to an instance of EOCClass is removed, it will continue to stay alive, thanks to the timer retaining it. The timer will never be released, because the instance holds a strong reference to it. Worse still, this instance will be lost forever because there are no more references to it other than through the timer. But you don’t have any references to the timer other than through the instance. This is a leak. It’s a particularly bad leak because the polling will continue to occur forever. If polling is downloading data from a network, data will continue to be downloaded forever, further adding to the potential leak.

Little can be done to alleviate this problem by using timers on their own. You could mandate that stopPolling be called before all other objects release an instance. However, there is no way to check for this, and if the class forms part of a public API that you expose to other developers, you cannot guarantee that they will call it.

One way to solve this problem is to use blocks. Although timers do not currently support blocks directly, the functionality can be added like this:

Click here to view code image

#import <Foundation/Foundation.h>

@interface NSTimer (EOCBlocksSupport)

+ (NSTimer*)eoc_scheduledTimerWithTimeInterval:
                           (NSTimeInterval)interval
                                     block:(void(^)())block
                                   repeats:(BOOL)repeats;

@end

@implementation NSTimer (EOCBlocksSupport)

+ (NSTimer*)eoc_scheduledTimerWithTimeInterval:
                           (NSTimeInterval)interval
                                     block:(void(^)())block
                                   repeats:(BOOL)repeats
{
    return [self scheduledTimerWithTimeInterval:interval
                                         target:self
                           selector:@selector(eoc_blockInvoke:)
                                       userInfo:[block copy]
                                        repeats:repeats];
}

+ (void)eoc_blockInvoke:(NSTimer*)timer {
    void (^block)() = timer.userInfo;
    if (block) {
        block();
    }
}

@end

The reason for doing this to solve the retain-cycle problem will become clear shortly. The block that is to be run when the timer fires is set as the userInfo parameter of the timer. This is an opaque value that the timer retains while it is valid. A copy of the block needs to be taken to ensure that it is a heap block (see Item 37); otherwise, it may be invalid when we come to execute it later. The target of the timer is now the NSTimer class object, a singleton, and it therefore does not matter if it is retained by the timer. A retain cycle remains here, but since the class object never needs to be deallocated, it doesn’t matter.

On its own, this solution does not solve the problem but merely provides the tools with which to solve the problem. Consider changing the problematic code to use this new category:

Click here to view code image

- (void)startPolling {
    _pollTimer =
    [NSTimer eoc_scheduledTimerWithTimeInterval:5.0
                                          block:^{
                                              [self p_doPoll];
                                                 }
                                        repeats:YES];
}

If you think about this one carefully, you’ll note that there is still a retain cycle. The block retains the instance because it captures self. In turn, the timer retains the block through the userInfo parameter. Finally, the timer is retained by the instance. However, the retain cycle can be broken through the use of weak references (see Item 33):

Click here to view code image

- (void)startPolling {
    __weak EOCClass *weakSelf = self;
    _pollTimer =
    [NSTimer eoc_scheduledTimerWithTimeInterval:5.0
                                          block:^{
                               EOCClass *strongSelf = weakSelf;
                               [strongSelf p_doPoll];
                                                 }
                                        repeats:YES];
}

This code uses a useful pattern of defining a weak self variable, which is captured by the block instead of the normal self variable. This means that self won’t be retained. However, when the block is executed, a strong reference is immediately generated, which will ensure that the instance is guaranteed to be alive for the duration of the block.

With this pattern, if the instance of EOCClass has its last reference to it from outside released, it will be deallocated. The invalidation of the timer during deallocation (check back to the original example) ensures that the timer will no longer run again. Using a weak reference ensures more safety; if the timer does run again for any reason, perhaps because you have forgotten to invalidate it during deallocation, weakSelf will be nil once in the block.

Things to Remember

An NSTimer object retains its target until the timer is invalidated either because it fires or through an explicit call to invalidate.

Retain cycles are easy to introduce through the use of repeating timers and do so if the target of a timer retains the timer. This may happen directly or indirectly through other objects in the object graph.

An extension to NSTimer to use blocks can be used to break the retain cycle. Until this is made part of the public NSTimer interface, the functionality must be added through a category.