Advanced programming tips, tricks and hacks for Mac development in C/Objective-C and Cocoa.

Rules to avoid retain cycles

Normally in Objective-C, if you follow the basic rule of maintaining a positive retain count for everything you need to hold onto and releasing when you're done, memory management will "just work" — until you create a retain cycle and suddenly no objects in the cycle will ever be freed. In this post, I'll explain retain cycles, common cases where they occur and the solutions to these problems.

Memory Management

All memory in a computer program must be allocated before it can be used and if you want to reuse that memory later for another purpose, it must be deallocated when you are done with it.

In garbage collected environments, programmers don't need to handle the allocation and deallocation themselves; the allocation, retaining, releasing and deallocation are handled automatically — but these steps still occur. Unfortunately, this automatic work is CPU and memory hungry; garbage collection is slower and takes more memory than manual memory management.

So, on the iPhone and in performance critical Mac OS X applications, we still have to handle memory management ourselves and that means methodically following the rules of Objective-C memory management:

  1. If you want to "own" an object, you must alloc, copy or retain it.
  2. Always release or autorelease when you are done with an object.

Unfortunately, if a retain cycle occurs, these rules are not enough to guarantee memory is freed correctly.

Object hierarchies and retain cycles

A quick explanation of retain cycles requires that I quickly summarize how hierarchies of objects are tied together. Specifically: objects in a hierarchy are created, owned and freed in a chain along the hierarchy.

retaincycle1.png

In this example, "Some Object" owns Parent which in turn owns the Child.

When the hierarchy is no longer needed, "Some Object" sends a release to the Parent. The Parent's retainCount hits zero, causing its dealloc method to run. In its dealloc method, it sends a release to the Child, successfully freeing the chain. This is the correct behavior.

The problem of retain cycles occurs when the Child needs a pointer to the Parent for any reason and it chooses to retain the Parent. This alters the diagram to the following:

retaincycle2.png

In this diagram, when "Some Object" sends a release to the Parent, the retainCount does not reach zero (since the Child's retain of the Parent has incremented the retainCount for itself). Since the Parent's retainCount does not reach zero, its dealloc method never gets called and so it never sends a release to the Child.

This is a retain cycle: with the Parent retaining the Child and the Child retaining the Parent, they continue to exist, cut off from the rest of the objects in the program but keeping themselves alive. They have leaked.

Avoiding retain cycles rule #1: An object must never retain its parent

The first rule to avoid retain cycles is that an object must never retain its parent. This changes the previous diagram to the following:

retaincycle3.png

This is the easy case: an object should never retain its parent when it makes a pointer to the parent.

Notice that the term "weak pointer" is used. A weak pointer is one that does not retain its target.

Of course, now that the child doesn't retain the parent, the child must be aware of any situation where the parent becomes invalid (freed) and not use its pointer to the parent in that case.

So, either:

  • The parent must set the parent pointer in the child to nil when the relationship is broken.
  • or

  • The design must guarantee that the parent pointer is always valid for the child's lifetime (or if the parent uses autorelease to free children, valid except in the child's dealloc method).

These two options apply to weak pointers in general: once the target becomes invalid, the pointer must be set to nil or the design must otherwise prevent invalid use.

Generally speaking, the option of setting to nil is much safer. The only downside is that it requires a way of detecting the pending release of the target and nominating an object whose role it is to make that detection and update the pointer accordingly. It is easy here where the parent (the target of the weak pointer) knows about the child and is also the hierarchical manager of the child but not all retain cycles are one-to-one like this.

Avoiding retain cycles rule #2: no hierarchical ancestor can be retained

It may seem obvious but this is where retain cycles can be subtle: an object must not retain any of its parent's parents, or any of their parents.

retaincycle4.png

This rule applies to many different situations. Some important considerations in Cocoa:

  • If an object retains an NSArray, NSDictionary or NSSet that collection must not retain the object or any of its parents.
  • If an object retains an NSInvocation where one of the arguments is the object or one of its ancestors, the NSInvocation may not retain its arguments.

If you want to store a collection of objects that may include one or more parents, you may want to consider one of the collections capable of non-retained pointers ("weak" collections):

  • A CFArray, CFDictionary or CFSet with NULL for the callbacks structure. i.e.:
    CFArrayCreateMutable(NULL, 0, NULL);.
  • +[NSPointerArray pointerArrayWithWeakObjects] (Mac OS X only)
  • +[NSMapTable mapTableWithWeakToWeakObjects] (Mac OS X only)
  • +[NSMapTable hashTableWithWeakObjects] (Mac OS X only)

In the rare situation where you must put a parent into a collection which retains its contents (like NSArray) you can wrap the contents in a non-retained object NSValue. i.e.:

[arrayOfParents addObject:[NSValue valueWithNonretainedObject:aParent]];

Despite this non-retain requirement for direct ancestors, it is okay to retain non-direct ancestors. However, once an object retains a non-direct ancestor, it becomes a direct ancestor to the object it retains.

For example, consider a situation where one child of a parent retains another:

retaincycle5.png

Before the "senior" child retained the other, they were both level siblings. Once one child retains another, it becomes a direct ancestor to the other. This now "junior" child may not retain its senior sibling without creating a loop. Any connection from this "junior" child back to the "senior" child must follow the "weak pointer" rules.

If you have lots of sibling nodes that you'd like to connect in complex ways, it's best to leave the ownership to the parent and connect all the siblings using non-retained pointers.

Avoiding retain cycles rule #3: "Connection" objects should not retain their target

Any object which connects itself to an arbitrary target object, without knowing their relationship, must not retain its target.

Connection objects include:

  • objects with a target and action (like a button)
  • objects that take a delegate
  • observees (objects to which observers are added)

Lets consider this by looking at the example of a button in a user-interface. A button connects the view hierarchy (through the button's superview) to the target of its action (it invokes the action method on its target when clicked).

A button must not retain its target. The reason for this becomes clear when you consider that a connection may need to point to a parent object:

retaincycle6.png

This diagram models the common situation where button invokes a method on the controller. The "Parent" is the view controller, the "Child" is the view which contains the button and the "Object with connection" is the button.

Clearly, if the button retained its target, there would be a retain cycle.

Obviously though, this creates a management problem: the button's controller must ensure that its target is updated if the target disappears (since the button object won't notice on its own).

Responsibility for maintaining connections invariably lies with that object's manager — following the design of your code, you must decide which object is responsible for managing the connection and it must detect when the connection becomes invalid and set it to nil or delete the connection entirely.

Fortunately, in most situations the solution is straightforward: the target is ultimately the owner and controller of the connection object, so the target just needs to release its children correctly when it is released and the connection will never persist past the lifetime of the target.

Avoiding retain cycles rule #4: use "close" methods to break cycles

If you have a hierarchy that is difficult to work out, it may be easier to retain any object you wish, and implement a "close" method to address the problem of cycles. A "close" method is one that is guaranteed to be sent to an object when its primary function is complete.

An example of this is a retain cycle between two NSViews. If you want to create retain cycles between two views, then go ahead. All you need to remember to do is disconnect each view in its willRemoveSubview: method.

The willRemoveSubview: acts to warn each view about a pending removal from the display (an end to its primary function) and the method is sent regardless of retain count — so you can use it to break any possible retain cycles so that the object will be dealloc'd as normal when its parents release it.

Avoiding retain cycles rule #5: temporary retains must be temporary

Any of these rules can be broken for short periods of time — however the rule must by "unbroken" automatically, without further intervention, for example: when an animation or other triggered process completes.

This is particularly useful for actions expected to delete, disrupt, sort or rearrange hierarchies temporarily. You must remain mindful that this could inflate memory use if you hold on for too long, so only use this approach sparingly.

An example of a temporary broken rule is the NSURLConnection delegate. By default, a delegate should not be retained as it is the target of an arbitrary connection (see Rule #3). However, an NSURLConnection's use of its delegate is guaranteed to complete automatically (either by connection complete or by timeout) so this object can safely retain its delegate. To be a good citizen in this situation, the NSURLConnection also provides the cancel method which acts as a "close" and will release the delegate sooner if desired (although the release is deferred through the run loop; it is not synchronous to the method invocation).

Conclusion

You may be tempted to retain every object you use out of fear that it will disappear while you're using it. Unfortunately, you can't simply retain everything — you must be aware of the hierarchical structure and think about what you are retaining and why.

I've listed 5 rules here but if you want a simpler message to remember: an object may only retain something indefinitely if it is hierarchically senior. If you don't know which object is senior, you must work it out before you retain. If there is no clear senior object — you should redesign so that there is.

Temporary files and folders in Cocoa

If you need to use temporary files in your application and you search the Cocoa documentation for "temporary file", you're unlikely to find anything that explains how to create one. Since temporary files and folders are subject to a number of security issues and race conditions when done wrong, it is important to know the correct way to create them. I'll show you some code that you can copy and paste into your applications to create temporary files and folders safely.

Introduction

With large amounts of RAM on modern computers and alternatives such as the cache directories and application support directories, genuine temporary files are not needed in most Cocoa applications. Even when they are needed, for atomic write operations or for Core Data databases, Cocoa libraries often create them automatically.

Eventually though, you're likely to encounter a situation where you need to create a temporary file yourself. You need to be careful when creating temporary files because:

  • Predictable temporary file locations can be a security hole in your applications.
  • On Mac OS X, multiple users on the computer may have their own copies of your application open, so the creation must be atomic (safe when concurrent).

In addition to this, you must be able to find the correct directories to place your files, be aware of the lifetime of files in these locations and manage cleanup correctly when you are done.

Required steps

Choosing the right enclosing directory

The directory for temporary files needs to be writeable by the current user. This means that the directory will need to be user-specific.

The correct directory is almost always the one returned by the Foundation function NSTemporaryDirectory. This directory is unique for each user (so each user has write permissions to it).

If you choose this directory though, it is important to know that it is cleaned out automatically every 3 days but otherwise persists between application launches and reboots. This directory is in a hashed location (not predictable in advance) and is therefore safe against security issues associated with predicatable locations.

If you need a location that can persist longer than 3 days, you probably want to use the Application Support directory or a Cache directory instead. Both of these locations are permanent (until your application deletes the contents) but Application Support is considered "important data" and backed up by Time Machine, whereas Cache is considered "user deletable at any time" and is not backed up. The backup point is important: don't store large amounts of temporary data in a location that will fill someone's backup drive.

These alternate directories are obtained using the Foundation function NSSearchPathForDirectoriesInDomains with a first parameter of NSApplicationSupportDirectory or NSCachesDirectory, a second parameter of NSUserDomainMask (occasionally a different value if you need a directory shared between users on the system or network — but this is uncommon). This function returns an array but you'll normally get just one result if you use NSUserDomainMask and you'll need to append your bundle identifier to get a location unique to your application.

// an alternative to the NSTemporaryDirectory
NSString *path = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(
    NSCachesDirectory, NSUserDomainMask, YES);
if ([paths count])
{
    NSString *bundleName =
        [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"];
    path = [[paths objectAtIndex:0] stringByAppendingPathComponent:bundleName];
}

This path value can be used instead of the NSTemporaryDirectory() invocations in the code samples below.

Creating and opening a file or subdirectory

To avoid concurrency issues (race conditions), you need to choose a name for any file or directory placed directly in the temporary directory that is unique but which also can't be stolen by another process between choosing the name and creating/opening the file or directory. Even though NSTemporaryDirectory() is unique for each user, you still must avoid potential conflicts within the user's account.

To do this, we use the POSIX function mkstemp for files and mkdtemp for directories. The former will return an already open file descriptor for the file and the latter will have already created the directory for us.

We could simply generate a universally unique identifier (UUID) and use that for the filename but these IDs are guessable which can create security problems in obscure cases where we don't also check for a name conflict — better to use something that looks for a collision, in the extremely unlikely case that it occurs. If you must use a UUID filename instead of mkstemp for some reason, be certain that it is for non-critical data.

Creating a temporary file:
NSString *tempFileTemplate =
    [NSTemporaryDirectory() stringByAppendingPathComponent:@"myapptempfile.XXXXXX"];
const char *tempFileTemplateCString =
    [tempFileTemplate fileSystemRepresentation];
char *tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1);
strcpy(tempFileNameCString, tempFileTemplateCString);
int fileDescriptor = mkstemp(tempFileNameCString);

if (fileDescriptor == -1)
{
	// handle file creation failure
}

// This is the file name if you need to access the file by name, otherwise you can remove
// this line.
tempFileName =
    [[NSFileManager defaultManager]
        stringWithFileSystemRepresentation:tempFileNameCString
        length:strlen(tempFileNameCString)];

free(tempFileNameCString);
tempFileHandle =
    [[NSFileHandle alloc]
        initWithFileDescriptor:fileDescriptor
        closeOnDealloc:NO];

It is important to handle all reading and writing from the temporary file using this fileDescriptor or something created directly from the fileDescriptor like the NSFileHandle in this example. This guarantees the operation remains safe for concurrency — if the fileDescriptor is closed before use, a race condition could occur.

The "X"s in the file name are replaced by the unique hash for the file's name. You'll probably want to replace the "myapptempfile" name with something appropriate, although it isn't required (the file is guaranteed unique regardless).

Also notice the use of fileSystemRepresentation and stringWithFileSystemRepresentation:length: to convert to and from the C strings — this is helpful to handle weird path quirks on different filesystems.

Creating a temporary folder:
NSString *tempDirectoryTemplate =
    [NSTemporaryDirectory() stringByAppendingPathComponent:@"myapptempdirectory.XXXXXX"];
const char *tempDirectoryTemplateCString =
    [tempDirectoryTemplate fileSystemRepresentation];
char *tempDirectoryNameCString =
    (char *)malloc(strlen(tempDirectoryTemplateCString) + 1);
strcpy(tempDirectoryNameCString, tempDirectoryTemplateCString);

char *result = mkdtemp(tempDirectoryNameCString);
if (!result)
{
    // handle directory creation failure
}

NSString *tempDirectoryPath =
    [[NSFileManager defaultManager]
        stringWithFileSystemRepresentation:tempDirectoryNameCString
        length:strlen(result)];
free(tempDirectoryNameCString);

You can now use the tempDirectoryPath as the container for any files. As with the previous example, you probably want to replace "myapptempdirectory" with something appropriate to your application and usage.

Conclusion

You could simply create a file in the /tmp directory but this approach is filled with many problems — write permissions, concurrency issues, security issues and duration or persistence issues.

Fortunately, the code to create a temporary file or temporary directory is consistent — you can normally use these code samples without modification. The only choices you need to make is whether to use an alternative directory (like the Application Support directory or the Caches directory).

A simple, extensible HTTP server in Cocoa

HTTP is one of the simpler protocols to implement for communication between computers. On the iPhone, since there are no APIs for data synchronization or file sharing, embedding an HTTP server is one of the best ways to transfer data from your iPhone application to a computer. In this post I'll show you how to write your own simple but extensible HTTP server. The server classes will also work on Mac OS X (Cocoa un-Touched).

Introduction

In this post I will present the following sample application:

httpserver.png

The application is very simple: you can edit text and save it to a file (it is always saved to the same file).

While the application is running, it also runs an HTTP server on port 8080. If the path "/" is requested, it will return the content of the saved file. All other requests return a 501 error.

To transfer the text file from the iPhone application, just enter the IP address of the phone followed by ":8080" in any web browser.

HTTPServer and HTTPResponseHandler classes

The approach I use for an HTTP server involves two classes: the server (which listens for connections and reads data up to the end of the HTTP header) and the response handler (which sends the response and may choose to read from the connection past the header).

The key design choice for me was simplicity of each new response implementation: the server and response classes are designed so that a new response implementation need only implement three methods:

  • canHandleRequest:method:url:headerFields: — to decide if the implementation can handle a specific request
  • startResponse — to begin writing (or completely write) the response
  • load — all subclasses should implement the standard +[NSObject load] method to register themselves with the base class

It is just a tiny HTTP server but the approach should allow you to quickly integrate HTTP communications into any application.

Opening a socket for listening

Most server communications, HTTP included, begin by creating a socket for listening.

Sockets in Cocoa can be created and configured entirely using the BSD sockets code but it's often marginally easier to use the CoreFoundation CFSocket API where possible. Unfortunately, that only makes it marginally easier — we still have a large block of boilerplate code to throw down just to open a socket.

From the -[HTTPServer start] method:

socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM,
    IPPROTO_TCP, 0, NULL, NULL);
if (!socket)
{
    [self errorWithName:@"Unable to create socket."];
    return;
}

int reuse = true;
int fileDescriptor = CFSocketGetNative(socket);
if (setsockopt(fileDescriptor, SOL_SOCKET, SO_REUSEADDR,
    (void *)&reuse, sizeof(int)) != 0)
{
    [self errorWithName:@"Unable to set socket options."];
    return;
}

struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_len = sizeof(address);
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(HTTP_SERVER_PORT);
CFDataRef addressData =
    CFDataCreate(NULL, (const UInt8 *)&address, sizeof(address));
[(id)addressData autorelease];

if (CFSocketSetAddress(socket, addressData) != kCFSocketSuccess)
{
    [self errorWithName:@"Unable to bind socket to address."];
    return;
}

This is a large block of code but it's really only doing one thing: opening a socket to listen for TCP connections on the port specified by HTTP_SERVER_PORT (which is 8080 for this application).

There is some additional work because I like to specify SO_REUSEADDR. This lets us reclaim the port if it is open but idle (a common occurrence if we restart the program immediately after a crash or killing the application).

Receiving incoming connections

After the socket is setup, Cocoa handles a little more of the work so things get easier.

We can receive each incoming connection by constructing an NSFileHandle from the fileDescriptor above and listening for connection notifications

From the -[HTTPServer start:] method (immediately below the previous code):

listeningHandle = [[NSFileHandle alloc]
    initWithFileDescriptor:fileDescriptor
    closeOnDealloc:YES];

[[NSNotificationCenter defaultCenter]
    addObserver:self
    selector:@selector(receiveIncomingConnectionNotification:)
    name:NSFileHandleConnectionAcceptedNotification
    object:nil];
[listeningHandle acceptConnectionInBackgroundAndNotify];

When receiveIncomingConnectionNotification: is invoked, each new incoming connection will get its own NSFileHandle. If you're keeping track, that was:

  • 1 file handle (listeningHandle) manually created from the socket fileDesriptor to listen on the socket for new connections.
  • 1 file handle automatically created for each new connection received through listeningHandle. We'll continue to listen to these new handles (the keys in the incomingRequests dictionary) to record the data for each connection.

So, now that we've received a new, automatically created file handle, we create a CFHTTPMessageRef (which will store the incoming data) we receive over the file handle. We store these as the objects in incomingRequests dictionary to allow easy access to the CFHTTPMessageRef for each file handle

The CFHTTPMessageRef is both storage and the parser for the incoming data. We can invoke CFHTTPMessageIsHeaderComplete() every time we add data to check when the HTTP headers are complete and we can spawn a response handler.

The response handler is spawned in the -[HTTPServer receiveIncomingDataNotification:] method:

if(CFHTTPMessageIsHeaderComplete(incomingRequest))
{
    HTTPResponseHandler *handler =
        [HTTPResponseHandler
            handlerForRequest:incomingRequest
            fileHandle:incomingFileHandle
            server:self];
    
    [responseHandlers addObject:handler];
    [self stopReceivingForFileHandle:incomingFileHandle close:NO];

    [handler startResponse];
    return;
}

The server stops listening to the file handle for the connection at this point but it doesn't close it, since the file handle is passed to the HTTPResponseHandler so that the HTTP response can be sent back over the same file handle.

Flexible response handling

Exactly which subclass the +[HTTPResponseHandler handlerForRequest:fileHandle:server:] method chooses to return determines the entire content of the response. It does this by iterating over a priority ordered array of the registered handlers and asking each one if it wants to handle the request.

+ (Class)handlerClassForRequest:(CFHTTPMessageRef)aRequest
    method:(NSString *)requestMethod
    url:(NSURL *)requestURL
    headerFields:(NSDictionary *)requestHeaderFields
{
    for (Class handlerClass in registeredHandlers)
    {
        if ([handlerClass canHandleRequest:aRequest
            method:requestMethod
            url:requestURL
            headerFields:requestHeaderFields])
        {
            return handlerClass;
        }
    }
    
    return nil;
}

For this to work, all HTTPResponseHandlers need to be registered with the base class. The easiest way to do this is to add an implementation of the +[NSObject load] method to every subclass:

+ (void)load
{
    [HTTPResponseHandler registerHandler:self];
}

In the sample application, the only response handler other than the default is the AppTextFileResponse. This class chooses to handle the response when the requestURL is equal to "/".

From the AppTextFileResponse class:

+ (BOOL)canHandleRequest:(CFHTTPMessageRef)aRequest
    method:(NSString *)requestMethod
    url:(NSURL *)requestURL
    headerFields:(NSDictionary *)requestHeaderFields
{
    if ([requestURL.path isEqualToString:@"/"])
    {
        return YES;
    }
    
    return NO;
}

AppTextFileResponse then handles the entire response synchronously (before returning from the startResponse method) by writing the text file saved by the application as the response body.

- (void)startResponse
{
    NSData *fileData =
        [NSData dataWithContentsOfFile:[AppTextFileResponse pathForFile]];

    CFHTTPMessageRef response =
        CFHTTPMessageCreateResponse(
            kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1);
    CFHTTPMessageSetHeaderFieldValue(
        response, (CFStringRef)@"Content-Type", (CFStringRef)@"text/plain");
    CFHTTPMessageSetHeaderFieldValue(
        response, (CFStringRef)@"Connection", (CFStringRef)@"close");
    CFHTTPMessageSetHeaderFieldValue(
        response,
        (CFStringRef)@"Content-Length",
        (CFStringRef)[NSString stringWithFormat:@"%ld", [fileData length]]);
    CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response);

    @try
    {
        [fileHandle writeData:(NSData *)headerData];
        [fileHandle writeData:fileData];
    }
    @catch (NSException *exception)
    {
        // Ignore the exception, it normally just means the client
        // closed the connection from the other end.
    }
    @finally
    {
        CFRelease(headerData);
        [server closeHandler:self];
    }
}

The [server closeHandler:self]; invocation tells the server to remove this HTTPResponseHandler from the set of active handlers. The server will invoke endReponse when it removes this handler (which is where we close the connection — since this handler does not support keep-alive).

Work not implemented

The biggest task not handled in this implementation is parsing the HTTP request body.

The reason for this is that a general HTTP body solution is very complicated. The body's size may be specified by the Content-Length header but it need not be — so knowing where the body ends can be difficult. The body may also be encoded in one of about a dozen different Transfer-Encodings, including chunk, quoted-printable, base64, gzip — each of which require different processing.

However, I have never needed to implement a generic solution. It is normally easiest to determine what is needed for your specific needs and handle the HTTP body in accordance with those needs. You can handle the request body by overriding -[HTTPRequestHandler receiveIncomingDataNotification:]. The default implementation ignores all data it receives after the HTTP request headers.

Data handling note: the first time the -[HTTPRequestHandler receiveIncomingDataNotification:] method is called, the initial bytes of the HTTP body will already have been read from the fileHandle and appended to the request instance variable. If you need to read the body, either continue reading into the request object, or remember to include this initial data.

Another task not handled are Keep-Alive connections. These also need to be handled in -[HTTPRequestHandler receiveIncomingDataNotification:] and I've left a big comment on the method about what would be involved. The reality is that it's probably easier to set the Connection header field to close for every response to tell the client that you're not going to handle Keep-Alive (see the startResponse code sample above for an example).

The HTTPReseponseHandler priority does not take the requested Content-Type into account. If this is an important consideration for you, you might want to change how +[HTTPResponseHandler handlerClassForRequest:method:url:headerFields:] selects its handler.

Finally, this server does not handle SSL/TLS. It is intended for local network transfers where the network itself is relatively secure. If you are transferring over the open internet and want a secure connection, there's a lot to change and manage at the socket level. You could try it yourself but if security is really important, you probably shouldn't risk writing your own server — if you can arrange it, use a mature, TLS-enabled HTTP server and only handle the client-side in your application. Client-side security in Cocoa is very easy — it is automatic and transparent in CFReadStream and NSURLConnection.

Conclusion

Download the sample app TextTransfer.zip (45kB) which includes the HTTPServer and HTTPResponseHandler classes.

Just because mainstream HTTP servers are large, complex pieces of software, doesn't mean an HTTP server is necessarily large and complex — the core implementation here is only two classes, yet is flexible and configurable.

Of course, the end result is not intended for use as a complete web server solution, however it should work well as a small communications portal into your custom iPhone or Mac applications.

HashValue: an object for holding MD5 and SHA hashes

Hash values are small, convenient values that you can generate from larger blocks of data for easy indexing, sorting and tracking. The traditional approach for generating MD5 and SHA hashes on Unix platforms to is to use command-line programs like openssl and md5. Apple provide easier approaches in the CommonCrypto library: here's how to use it, along with an NSValue subclass to wrap the result for interoperability with other Cocoa classes.

Introduction to hashes

A hash value is a small, convenient number used to track or sort an arbitrary block of data.

A real-world example of a hash value is the initial letter in a word. You can use the initial letter of a word to lookup that word in a dictionary. If two words have different starting letters, they cannot be equal but if two words have the same starting letter, that doesn't guarantee they are the same.

For fast searching, you can immediately see the problem with only using an initial letter: if all you had to look up a word was its initial letter, you'd still have thousands of words to go through that all start with the same letter. You could use the first four letters but some combinations will be rare (like "aard") but others will contain hundreds of matches (like "stra").

In computing, we rarely ever use the first values in a block of data to track that block of data. Starting values of blocks of data are too often the same or similar — especially in the common case where we are sorting data that already has traits in common.

Instead, we use hash functions that use relatively complex mathematics to generate values from the source data that are well spread, even for source data that is nearly identical. Fortunately, you don't need to know the underlying mathematics, all you need to know is that a hash value can be used to:

  • check if two blocks of data are the same
  • sort data into hash tables
  • checksum data (make certain your data hasn't changed)

Though these are the main purposes for which you should use hashes, MD5 and SHA hashes were actually developed for cryptography, not basic data handling. Nevertheless, for encryption and password handling in your own applications, I recommend using the Keychain (Security.framework) rather than manually using cryptographic hashes.

Generating an MD5

MD5 is one of the most common hash functions. While it is no longer considered safe for security, its use as a checksum is very common.

The traditional Unix approach is to use the md5 program on the command-line:

matt$ md5 -s "Some data value."
MD5 ("Some data value.") = db7116c8634ad7fe3bd90bee94274ee0

The 32 character hexadecimal string is a human readable representation of the 16 byte output of the MD5 function.

On the Mac and iPhone, we can generate this value as follows:

#import <CommonCrypto/CommonDigest.h>

char input[] = "Some data value.";
char result[16];
CC_MD5(input, strlen(input), result);

However, we frequently want the human-readable hexadecimal string. The following will produce an identical ouput to the previous command-line invocation:

printf("MD5 (\"%s\") = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
    input,
    result[0], result[1], result[2], result[3], 
    result[4], result[5], result[6], result[7],
    result[8], result[9], result[10], result[11],
    result[12], result[13], result[14], result[15]);

Producing other kinds of hash works in the same way. e.g. For SHA256, use CC_SHA256 instead of CC_MD5 and increase the size of the result to 32 from 16.

The HashValue class

Since hash values are frequently used to track blocks of data in a program, it would be nice to have an Objective-C class that wraps the hash values so we can use them in NSDictionary objects as keys for our data.

If we consider a hash value simply as a small C struct, i.e:

typedef struct
{
    char value[CC_MD5_DIGEST_LENGTH];
} HashValueMD5Hash;

typedef struct
{
    char value[CC_SHA256_DIGEST_LENGTH];
} HashValueShaHash;

then the easiest way to make it a fully fledged Objective-C object is to create an NSValue from it:

char input[] = "Some data value.";
HashValueMD5Hash result;
CC_MD5(input, strlen(input), &result);

NSValue *myHashValue = [NSValue valueWithBytes:&result objCType:@encode(HashValueMD5Hash)];

That's an okay solution but if you're generating a lot of hashes in your program, it would be good to have a class that:

  • has an optimized construction method that can generate the hash directly from NSData
  • abstracts away the C struct so you can deal exclusively with the Objective-C objects
  • overrides the description method to easily generate human-readable strings

So I wrote the HashValue class.

@interface HashValue : NSObject <NSCoding, NSCopying>
{
    unsigned char value[HASH_VALUE_STORAGE_SIZE];
    HashValueType type;
}

- (id)initMD5HashWithBytes:(const void *)bytes length:(NSUInteger)length;
+ (HashValue *)md5HashWithData:(NSData *)data;
- (id)initSha256HashWithBytes:(const void *)bytes length:(NSUInteger)length;
+ (HashValue *)sha256HashWithData:(NSData *)data;

- (const void *)value;
- (HashValueType)type;

@end

Despite being a class that wraps a value, there's no explicit reason to make it a subclass of NSValue. Since subclassing NSValue has inherent difficulties (you need to carefully override a lot of inherited methods) I've made the class a basic subclass of NSObject.

The init method implementations are fairly simple:

- (id)initMD5HashWithBytes:(const void *)bytes length:(NSUInteger)length
{
    self = [super init];
    if (self != nil)
    {
        CC_MD5(bytes, length, value);
        type = HASH_VALUE_MD5_TYPE;
    }
    return self;
}

The description method is overridden to provide the human-readable hexadecimal string:

- (NSString *)description
{
    NSInteger byteLength;
    if (type == HASH_VALUE_MD5_TYPE)
    {
        byteLength = sizeof(HashValueMD5Hash);
    }
    else if (type == HASH_VALUE_SHA_TYPE)
    {
        byteLength = sizeof(HashValueShaHash);
    }

    NSMutableString *stringValue =
        [NSMutableString stringWithCapacity:byteLength * 2];
    NSInteger i;
    for (i = 0; i < byteLength; i++)
    {
        [stringValue appendFormat:@"%02x", value[i]];
    }
    
    return stringValue;
}

Most of the other methods in the class are basic accessors or NSCopying, NSCoding and NSObject methods. The copying methods in particular are essential so that the object can be used as a key in an NSDictionary.

I will highlight one other method:

- (NSUInteger)hash
{
    return *((NSUInteger *)value);
}

You may wonder why it's necessary to have a hash method on a class that is itself a hash value. Hash methods in Cocoa are used for the same indexing and sorting tasks I identified above: sorting and finding objects in NSSet and NSDictionary. In Cocoa the default hash method calculates its hash value from the memory address of the object. Because we have overridden isEqual: to compare the object's internal value, we also need to override the hash method to also reflect this change. This is a basic requirement of hashes — equal objects must return the same hash value (imagine the confusion if two identically spelled words were sorted to different locations in a dictionary).

It may seem a little odd to simply return the first few bytes of the value as our new hash (after I explained that the first few bytes is rarely the best hash) but this case is an exception to the rule: our data is already "well-spread" and every bit in our hash is as well-spread as the next.

Conclusion

You can download the HashValue class as a .zip file (2kB)

Hash values are used everywhere. Git uses SHA1 to track file changes in its repository, BitTorrent uses MD5s to identify torrents and many download programs use hashes to checksum downloaded data.

The CommonCrypto library (part of Foundation on the Mac and iPhone through libSystem) makes generating common hash functions very simple.

As with all data manipulation, I think a nice Cocoa class around the data makes it easier to use. I have only added MD5 and SHA256 to this particular implementation but it should be very simple to add other CommonCrypto hashes to the class should you require them.

Custom views in Interface Builder using IBPlugins

If you have custom views configured in code, it can be time consuming to configure them for each instance and make them look right in context. To make the process smoother, you can create Interface Builder plugins and configure your objects in Interface Builder. While the Xcode documentation explains how to do this, it is long, thorough and confusing. Here is the simplified set of steps that I use to create Interface Builder plugins quickly.

Introduction

Apple do have extensive documentation on Interface Builder Plugin creation. However, their documentation is thorough enough that may be overwhelming the first time you want to write an Interface Builder plugin.

I also find the workflow in Apple's IBPluginGuide very different to my typical workflow. I think this is because I normally just want an existing class to show up in Interface Builder so I can tweak one or two attributes — the processes for creating a redistributable library of components is more than I need.

So I was inspired to write this post: a shorter, workflow-optimised version of the same process described in the IBPluginGuide — using Interface Builder to configure a custom button.

A custom buttom

Consider the button in the following window:

ibplugin1.png

A big, drab, gray button. Maybe gray is an acceptable default but it doesn't really match this window. This post will make it easy to adjust this color in Interface Builder.

The large gray button here uses a custom button cell which draws the button using the Gloss Gradient from one of my earlier posts. The drawing code is:

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    NSBezierPath *roundRectPath =
        [NSBezierPath
            bezierPathWithRoundedRect:NSInsetRect(cellFrame, 2, 2)
            xRadius:5
            yRadius:5];

    NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
    [graphicsContext saveGraphicsState];
    [roundRectPath addClip];

    DrawGlossGradient(
        [graphicsContext graphicsPort],
        self.buttonColor, // <-- this determines the color of the button
        cellFrame);

    if ([self isHighlighted])
    {
        [[NSColor colorWithCalibratedRed:0.0 green:0.15 blue:0.35 alpha:0.5]
            set];
        [roundRectPath fill];
    }
    [graphicsContext restoreGraphicsState];

    [[NSColor lightGrayColor] set];
    [roundRectPath setLineWidth:2.0];
    [roundRectPath stroke];

    [self drawInteriorWithFrame:cellFrame inView:controlView];
}

This is all fine except that the color of the button is determined by the self.buttonColor property and if we have to choose this in code (continually changing the value, fixing, continuing, refreshing and repeating) it could get very time consuming.

A better solution would be to edit the button's color in Interface Builder. That way, we will be able to use color sliders to update the button drawn in the complete context of the window, in real-time.

Creating the IBPlugin project

My process normally starts by creating a custom view component. In this case, I have already created a class named CustomButtonCell in the project for my main application (AppWithButton). After creating the class, I have decided it would be a good idea to have an Interface Builder Plug-In.

A quick point about class requirements: every property we want to configure in Interface Builder must be encoded and decoded for the object using implementations of the NSCoder protocol methods initWithCoder: and encodedWithCoder: overrides. Download the project linked below to see how this is done.
1. Create and name the project

"Interface Builder Plug-In" is a project template in Xcode. In the New Project window, it's in the "Mac OS X -> Standard Apple Plug-ins" section.

An important point to consider is the name for the project — it should not be the same as the custom view component (in this case, CustomButtonCell) because the template will create a class with the name and it can't conflict with the existing view component.

I chose "ButtonPlugin" and saved the new project in the folder for my existing AppWithButton project.

2. Make the new project use the existing CustomButtonCell
Delete the default files and insert our own

The template creates a custom view in the ButtonPlugin project. I never use this (since I want to use my existing view). So I delete the ButtonPluginView.m, ButtonPluginView.h references and files.

I add my CustomButtonCell.m and CustomButtonCell.h files to the ButtonPlugin project but I don't copy or move the files — I leave the files at their current locations in AppWithButton project but drag them into the ButtonPlugin's Source Tree.

Make certain these new files get built

You need to check that the CustomButtonCell.m is added to the Compile Sources build phase of the ButtonPluginFramework Target and the CustomButtonCell.h is added to the Copy Headers build phase of the ButtonPluginFramework. Neither should appear in the ButtonPlugin target.

Then, select the "CustomButtonCell.h" file from the "Copy Headers" build phase and in the Detail View, change the "Role" from "Project" to "Public". This is a pretty obscure thing to do. I normally don't have the Detail View visible — if you don't know which view is the Detail View, it's time to learn because there is no other way to change this value in Xcode.

ibplugin3.png

Change the Role of the "CustomButtonCell.h" to "public" in the Detail View

Rename the file ButtonPluginViewIntegration.m to CustomButtonCellIntegration.m and replace every occurrence of ButtonPluginView in this file to CustomButtonCell.

3. Prepare all the other files in the project

Make the following file changes:

  1. Find the ButtonPluginView.classdescription and rename this file to CustomButtonCell.classdecription (same as our custom cell).
  2. In the contents of this file, change the ClassName to match the actual class name CustomButtonCell and change the SuperClass to be NSButtonCell (again, matching the actual super class for our custom button cell).
  3. In ButtonPlugin.m (the top level class in the ButtonPlugin project), set the bundle identifier to something appropriate. I used com.mattgallagher.ButtonPlugin — this needs to be unique among Interface Builder plugins, so you pick an appropriate value each time.
  4. Set the bundle identifier in the Info.plist and the ButtonPlugin-Info.plist to the same com.mattgallagher.ButtonPlugin value.
4. Configure the display of the button cell for the Interface Builder Library panel

Open the ButtonPluginLibrary.nib. This file contains the "Library Object Template" view (an instance of IBLibraryObjectTemplate). You can find it in the "Library Objects" view at the top level.

Delete the library template that doesn't apply

The Library Object Template will contain a "Template" and an "Example" square. The "Template" version is for NSView subclasses but our CustomButtonCell needs to be embedded in another object (an NSButton) so we will use the "Example" square — so delete the "Template" square.

Set our custom class in the library template

If you click on the button in the "Example" square then click again, it will select the NSButtonCell inside the button (these clicks should be slower than a double-click, since a double-click will edit the text of the NSButton instead of selecting the NSButtonCell inside). With the NSButtonCell selected:

  1. Type Command-6 to select the correct inspector panel.
  2. Enter the custom class name in the "Class" field of the inspector — in our case, we need this to be CustomButtonCell.
  3. Set the button cell class for the NSButton to the right of the "Example" box in the same way.

Select the Library Object Template (ButtonPluginLibrary.nib window -> Library Objects -> Library Object Template) and:

  1. Type Command-1 to select the correct inspector panel.
  2. Fill in the "Label", "Summary" and "Description" for your Library Object as you choose. I like to delete the Path and leave it blank but you can add a path if you want to categorize your custom classes.
5. Configure the Interface Builder Inspector panel

Back in the ButtonPlugin project again, open the ButtonPluginInspector.xib.

Set all the controls in the Inspector panel how we want them

I deleted everything in the "Inspector View" window except 1 label and the NSColorWell. I moved these controls to the top of the view and then made the view 35 pixels high.

Connect the controls so they act on our object

To make the color selector do something, I used bindings. Select the NSColorWell and:

  1. Type Command-4 to select the correct inspector panel.
  2. Under the "Value" subheading, bind to File's Owner (make sure the checkbox is selected too).
  3. Set the Model Key Path to inspectedObjectsController.selection.buttonColor.

This binding needs one other change to work. Back in the ButtonPlugin project, open the CustomButtonCellIntegration.m file. Change the [[keyPaths objectForKey:IBAttributeKeyPaths... line to:

[[keyPaths objectForKey:IBAttributeKeyPaths]
    addObjectsFromArray:[NSArray arrayWithObjects:@"buttonColor", nil]];

This tells Interface Builder to track and monitor the buttonColor property on the CustomButtonCell class. It does not actually perform the value changing (the binding we established will change the value directly) but it will make certain that this value will be tracked for undos and can be edited correctly.

Using the IBPlugin

At this point, you can run the ButtonPlugin project and it will launch Interface Builder with the plugin visible. The only problem is that the plugin won't be visible if you launch Interface Builder in any other way.

Build Settings

The following steps will make the ButtonPlugin project build the ButtonPlugin.framework and ButtonPlugin.ibplugin and install it in your Library.

Double click the ButtonPlugin project item in the ButtonPlugin project Source Tree to edit the project settings. Select the "Build" tab, then choose "Configuration: All Configurations". Then make the following changes:

  1. Set the "Deployment Location" checkbox to checked.
  2. Set the "Installation Build Products Location" to "$(HOME)/Library/Frameworks".
  3. Set the "Installation Directory" to "/".

Double-click the "ButtonPlugin" target in the Source Tree to edit that target's settings. Select the "Build" tab, then choose "Configuration: All Configurations". Then make the following change:

  1. Set the "Installation Directory" to "/ButtonPlugin.framework/Resources.
And now it's installed

With these changes made, build and run the ButtonPlugin project and it will install the ButtonPlugin.framework in your ~/Library/Frameworks directory and load it in Interface Builder. From now until you remove the framework from your library, it will remain in Interface Builder and you can use it at any time.

I realize that this configures the app to install the "Debug" build in the user's library, over the top of the "Release" build (if the Release build is already built) but this is really just for local use, so I don't really care. If you do care, you might not want to apply these settings to all configurations. For me: this is faster to implement and easier to manage.

Integration with the original AppWithButton project

After setting up the Interface Builder plugin, instance of CustomButtonCell in your existing .xib and .nib files will not instantly update. You'll probably need to create new versions of the cell by dragging them out from the Library.

In this example, I have chosen to not link the original AppWithButton project with the ButtonPlugin.framework. This is because I don't want to distribute either the framework or the plugin — they are both for my purposes only.

If you wanted to link them, you could remove the CustomButtonCell.m and CustomButtonCell.h files from the original project and replace them with the ButtonPlugin.framework. According to the Xcode documentation, this arrangement would allow you to avoid installing the ButtonPlugin.framework in your ~/Library/Frameworks directory (Interface Builder would automatically find the plugin for any .nib or .xib file in the project). That's a nice idea but it has never worked for me, so I never bother.

Set a build dependency to keep ButtonPlugin up-to-date

Instead, I like to drag the ButtonPlugin.xcodeproj file into the AppWithButton Source Tree and edit the AppWithButton target, go to the "General" tab and add the ButtonPlugin.xcodeproj as a Direct Dependency.

The reason for this is that if I change the CustomButtonCell class and rebuild, it will automatically rebuild the Interface Builder plugin accordingly (you need to restart Interface Builder to see the changes).

ibplugin2.png

The AppWithButton window in Interface Builder, adjusting the color of the button in real-time.

Conclusion

You can download the complete AppWithButton project zip file (including the ButtonPlugin project) (385kB).

It takes quite a few steps to set up an Interface Builder plugin. Fortunately, they're all simple, if a little menial.

Notice how little code was actually written though: bindings and Objective-C 2.0 properties make this whole process considerably easier — there is no actual code written to set the buttonColor (except in the NSCoder method implementations) since the bindings do it all for us.

Once you're practiced at making plugins in this way, the effort to create one may be justified, even just to tweak simple properties like this.

Do I know how to do this for Cocoa Touch classes for iPhone development? No. I imagine it's possible but you'd need to completely change the IBPlugin project from the template and I've never tried.