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

Application Design in AppKit

This is a discussion of high-level application design in Cocoa that aims to explain the major class roles in an AppKit application and how they are connected. I'll show you much more detail than simply "Model-View-Controller" and I also give a specific example of how all the concepts apply to a real application.

The anecdote

The other day, I was showing a friend how to program in Cocoa. She is a very good programmer but has never really programmed a user-application — working almost exclusively on embedded and server applications.

The experience reminded me that even good programmers can be unaware of basic design traits of user-applications which, while common to user-applications on all platforms, are not common to all programming.

So even though it's more "novice" than my regular fare, it would appear that even simple topics can be useful to advanced programmers.

A starting point

"Model-View-Controller" is the term normally used to describe the structure of modern applications. Almost every discussion of application design begins with it and I guess I will too. It looks like this:


Your document data (the "model") notifies the intermediary (the "controller") and it tells your user interface elements ("the view") to update. Going back in the other direction, user actions in the user-interface trigger notifications to the intermediary which modifies the data.

The rationale may not be immediately obvious. Let me explain it this way:

    User applications are big and complex — even seemingly simple applications. To manage complexity, everything is compartmentalised. To keep the boundaries between compartments clean, connections between compartments should be simple and generic.

Obviously, you don't want the model and view to be the same thing because then, there is no separation at all and the application will be a tangled mess.

Direct connections between model and view are normally frowned upon because it creates a situation where they must know too much about each other's internal state to interoperate. Instead, a controller object (which knows about connective state but little else) is used to keep the interaction simple and generic.

Better than Model-View-Controller

These traits of Model-View-Controller are all good things but in reality, it says little about how to assemble an application. Real applications have many more traits in common than a separation between model and view.

A more complete diagram of a typical application's design would look like this:


In this diagram, solid black arrows indicate construction and hierarchic ownership. Feint gray arrows indicate communication in response to changes.

Application instance

The application instance incorporates the program entry point and the event loop (which handles all user events like mouse and keyboard actions). As the starting point of the program, the application instance constructs the other top-level objects in the program.

Application controllers

The term "Application User Interface" is used in this part of the diagram to refer to elements of the user-interface that are not part of the document or the main window.

These objects are constructed by the application at startup. They should only handle things which exist before the main window or main document is open or which fall outside the bounds of these areas. Example behavior here includes the application preferences window and the Mac OS X menu bar.

Document instance

This is the first point where a programmer begins to exercise significant control over the program's behavior. The document loads or constructs the program's data and constructs the windows to show it.

A common mistake is to think that your program doesn't have a "document" so you shouldn't model a document class. In reality, if a program does anything then it is changing some piece of data (a preference file, a set of objects for rendering in OpenGL, the result of a calculation). You should design your program with this piece of data as the document. Even if your program only has one window, even if it only works with the same piece of data, even if you aren't writing a "Cocoa Document-based Application"; you should always have a class at the heart of your program which can be called "the current document".

Window controllers

A window controller is the class responsible for loading a window and putting it on screen. The window controller is responsible for giving context to the views and controls within the window, connecting them to data controllers which will provide them with data.

It is common for window controllers to double as data controllers for some functions since the window controller knows the state required to make the connection. This is not a bad thing in itself but should be resisted in the long term since it leads to bloat in the window controller (which often has a lot of work to do already). Generic, data-specific controllers should be used for this task.

User Interface Elements

Where possible, these should be generic elements: buttons, text display, image display. They end up performing specific actions when connected (through controllers) to their contextually supplied data.

User interface elements are normally hierarchic. The screen contains windows; windows contain views; views contain subviews. One window is normally in front (main window) and one view within this window is normally the focus. The application's "event loop" will send keyboard actions, mouse events and menu selections to this focus object. Unhandled events get passed up through the hierarchy so that parents can handle events that their children don't handle.

The handling of events should be managed as low in the hierarchy as possible. Again, consolidation in parents leads to bloat. Even "small" applications can become very big.

Data Controllers

These should be as generic as possible. Their purpose should be to relay information from a source to a destination about data changes.

The simplest manifestation of a data controller is for a third-party to establish or enable the Observer design pattern between two objects.

The worst approach (sometimes called an anti-pattern) is an all encompassing arbiter object that receives every change request the program makes, performs the change and then updates everything that needs to be updated. This approach is unsustainable on an application-wide scale. Decomposition is key — data controllers should have small, focussed scope.

An example application

Now we'll look quickly at what this means in an AppKit-based application. This application is a simple program that creates and edits lists of names. I know that's a pretty trivial thing for a program to do but the example must be simple so I can describe it here properly.

You can download the project described in this diagram, although it isn't necessary to understand the discussion.

The application object is an unmodified NSApplication. This will almost always be the case in any Cocoa Application. You can achieve most customisation of the NSApplication object through data (in the Info.plist file) or by attaching an application delegate object (which can intercept control at predetermined points). The application instance handles our startup, event loop and contruction of documents (I have discussed how a Cocoa application loads in a previous post).

This application doesn't have any preferences or significant data outside the scope of the document, so the "Application Controllers" section just has the Main Menu in it.

Documents in AppKit act as both a data controller for the data (in this case, an array of strings) and the window controller for the main document window. The document handles saving and reading to and from any file on disk. This could be done with basic NSKeyedArchiver methods to turn an array of strings into an NSData object for writing to disk. The window is loaded automatically from the window NIB file (specified in the program's Info.plist file).

The NIB file for the document contains an NSArrayController which is connected to the list of names from the document via the appropriate keyPath. This allows the NSArrayController to issue key value observing notifications when it changes the array and similarly allows it to update automatically when something else changes the array on the document.

The NIB file for the document also contains the window, which in turn contains an NSTableView. The NIB file specifies that the NSTableView's only column (displayed using the NSTextCell) should get its data from the NSArrayController. In this way, the table is updated to display the list of names contained in the document.

The NSTextCell displays the name for each row and allows editing. If an entry is changed in this way, notifications are sent back through the NSArrayController to the document.

Similarly, the "Add New Name" button can add a new object by communicating with the NSArrayController, asking it to create a new object and insert it in the array, which triggers all relevant change propagations.


All of this may seem like a lot of work — setting up connections and controllers and notifications. When starting a new program, you may think that many of these elements don't apply to you. Be careful — don't chase false simplicity.

Remember, Cocoa was written to make the approach described in this article easier than the alternatives. Classes like NSArrayController and protocols like NSKeyValueObserving and NSKeyValueBindingCreation make connecting large amounts of data as simple as point and click in Interface Builder. In many cases, it ends up being faster than manually connecting a button or text field directly to a method on your document class.

You will always have change behaviors that cannot be connected using these generic objects but following the same structural patterns that they use will keep your application clean and make it work better within Cocoa.

Safely fetching an NSManagedObject by URI

If you need to store a reference to an NSManagedObject outside of an NSManagedObjectContext, then you'll need to convert NSManagedObjects to URIs and back again. At first glance it looks like a simple method will do all the work for you but in reality you must be careful when getting the object back. I'll show you the way to convert an object to a URI and get it back safely.

Why store an NSManagedObject reference outside a context?

Perhaps you want to store cross-store relationships. Perhaps you want to copy references via the clipboard or a dragging pasteboard. Maybe you want to store the last accessed object in your preferences.

None of these storage locations are within an NSManagedObjectContext. So if you want to store an NSManagedObject reference reliably, you can't just store a pointer.

If one of the attributes on your entity is guaranteed unique, you could store that attribute and use it to find the NSManagedObject later. But you don't need to add a unique attribute: every object already has one provided automatically — the objectID.

— Matt, if you love Core Data so much, why don't you marry it?
Okay, I've written quite a few Core Data related posts now (relative to other frameworks within Cocoa). That's because it's an amazing API: free file reading/writing, free undo, scaleable, highly optimised. Unless you have explicit reasons to avoid it, every program you write should use it.

The easy part: convert to a URI

It's very easy to create a URI from an NSManagedObject and the documentation explains this well.

NSURL *uri = [[myObject objectID] URIRepresentation];

Once it's an NSURL, you can serialize it (for use in pasteboards, etc) with:

NSData *uriData = [NSKeyedArchiver archivedDataWithRootObject:uri];

What is a URI?

In Core Data, a URI uniquely identifies an object. It is normally viewed as a string:

e.g. x-coredata:///MyEntity/t03BF9735-A005-4ED9-96BA-462BD65FA25F118 (temporary ID)
or x-coredata://EB8922D9-DC06-4256-A21B-DFFD47D7E6DA/MyEntity/p3 (permanent ID)

In a more general context, it stands for "Uniform Resource Identifier" and could be a URL ("Uniform Resource Locator") or a URN ("Uniform Resource Name") or both.

A URN uniquely identifies an entity (for example an ISBN number uniquely identifies a book) but doesn't tell you where to find that entity. A URL tells you a location but doesn't let you uniquely identify the object that you find there (for example, you may be able to download the PDF of a book from a web address but without extra information can't tell if it matches a given ISBN).

If you duplicate a Core Data file on disk, then you end up with two files that have the same persistent store ID. So Core Data URIs are not always globally unique but in practice that distinction rarely matters.

Problems getting the NSManagedObject back

NSPersistentStoreCoordinator has the method:

-(NSManagedObjectID *)managedObjectIDForURIRepresentation:(NSURL *)uri;

and NSManagedObjectContext has:

-(NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID;

so it would seem that all you need to do is convert your string to an NSURL, convert the NSURL to an NSManagedObjectID and the NSManagedObjectID to the NSManagedObject.

But there's a catch: these methods do not actually fetch the object from the persistent store. If the object doesn't exist, these methods will still succeed, giving you an NSManagedObjectID or NSManagedObject referencing a non-existent entry in the persistent store (which will throw an NSObjectInaccessibleException if you try to fault it). The reality is that, despite their appearance, these methods are for constructing object ID's, they don't search the persistent store.

Obviously, we will need to combine these methods with a proper search of the persistent store.

Safely getting the object back

If the NSManagedObject for the URI does eixist and has already been faulted by the NSManagedObjectContext, then the result from objectWithID: will be the correct object. The question is how to handle the situation where isFault returns NO (and the object may not exist).

The answer is: even though the NSManagedObject returned by objectWithID: may not exist in the persistent store, we can still use the NSManagedObject to search the persistent store.

Time for a whole chunk of code. This is an NSManagedObjectContext category that returns the faulted object for the given URI string, if it exists, or nil if it doesn't.

You may notice that I construct the NSPredicate for the search directly in code (instead of using a predicate string. I wanted to waste as little CPU time as possible.

@implementation NSManagedObjectContext (FetchedObjectFromURI)
- (NSManagedObject *)objectWithURI:(NSURL *)uri
    NSManagedObjectID *objectID =
        [[self persistentStoreCoordinator]
    if (!objectID)
        return nil;
    NSManagedObject *objectForID = [self objectWithID:objectID];
    if (![objectForID isFault])
        return objectForID;

    NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
    [request setEntity:[objectID entity]];
    // Equivalent to
    // predicate = [NSPredicate predicateWithFormat:@"SELF = %@", objectForID];
    NSPredicate *predicate =
                [NSExpression expressionForEvaluatedObject]
                [NSExpression expressionForConstantValue:objectForID]
    [request setPredicate:predicate];

    NSArray *results = [self executeFetchRequest:request error:nil];
    if ([results count] > 0 )
        return [results objectAtIndex:0];

    return nil;

That's it. By executing the search when the object is a fault, we correctly guarantee its existence.

In defense of Objective-C 2.0 Properties

Of all the new features in Objective-C 2.0, none were as controversial as declared properties. Judging from the attacks, much of the controversy stems from a misunderstanding about the role that properties occupy in a class. In this post, I'll explain why properties are useful in Objective-C — and it isn't auto-generated getters and setters or the dot syntax.

Confusion, controversy and hate

My esteemed colleagues in the world of Objective-C blogging are not universally friendly towards Objective-C 2.0's Properties. In case you've missed the vitriol, let me draw your attention to:

I love a good drama. And next season, I hear that the show's writers are really going to knock it up another notch.

Not the purpose

The syntax used for accessing properties is the direct target of most hatred. Detractors claim that the syntax is a pointless, foreign addition and that existing method syntax could be used instead. I think such complainants misunderstand the purpose of properties which leads to misunderstanding the purpose of the dot syntax.

So let's start by clarifying the purpose of properties. Let me state very clearly:

  1. The purpose of properties is not to provide auto-generated getter and setter methods.
  2. The purpose of properties is not to replace method syntax with dot syntax.
  3. The purpose of properties is not to make attributes public in a different way.

Obviously, these things can occur through properties but if they do, then they are an artefact or convenience offered by the implementation while working towards the real purpose.

As support for these statements, let me point out:

  1. Auto-generated methods are a convenience permitted because properties clearly declare how they are accessed. But they are a convenience, not a rationale. Many properties do not use the @synthesize feature.
  2. Properties and methods are distinct concepts and should never be used with the other's syntax. Syntax interchange is possible as an artefact of Objective-C's implementation of properties, not an invitation to exploit confusion.
  3. Properties do not require an ivar of the same name. They may use a different ivar or store the data in a completely different form. Properties and attributes are not directly related.

The purpose

A clean, abstracted way to expose state values of an object.
Properties are one of two metaphors exposed by an object, the other being Methods (which are "a clean, abstracted way to perform an action").

Attributes (ivars) do not occupt the same role as properties (even when public) because they are not abstracted. You cannot override an attribute. You cannot change how an attribute is stored and maintain interface compatibility.

Methods can perform the same work as a property (to fetch state or to set state) but they do so by contract not by design.

Prior to the introduction of properties, methods were required to perform the work of a property. To enable this, documentation had to explain that the method existed to access state, not perform an action. The same documentation also became filled with getter methods referring to their corresponding setter methods. Setter methods pointing out the appropriate getter methods.

Prior to properties, get and set access to state-like values existed but only because code in multiple places was loosely coupled to present a concept unsupported by the underlying language. Properties declare the existence of state values clearly and eliminate the separation between getter and setter methods.

New syntax is foreign but it needs to be new

The key complaint about the dot syntax is that the syntax looks foreign compared to Objective-C's message send syntax. Why use a new syntax at all? Why not simply invoke the underlying getter or setter methods directly?

Because properties are a different metaphor and imply different behavior and expectations than a method invocation.

Also, dot syntax allows the same syntax to be used for both get and set, keeping these two concepts properly tied together. Further, it keeps state access separate from performing actions.

That getter and setter methods are used to implement a property should be viewed as an implementation detail, not really part of the interface. To maintain abstraction, you should never directly invoke the methods of a property.

Abstraction overload

It is true that properties represent a new abstraction concept in Objective-C and there are some people who view more abstractions as bad as they lead to leaky abstractions. This is a fair complaint: don't use a new abstraction unless you are comfortable with it and you feel your code needs it. Do not use properties just because they are there.

Use properties if you want to separate state and action, gaining the advantage of implicitly conveyed meanings.

With respect to traditional accessor methods, properties imply "always accessible" (no special setup required). Properties imply "short and simple" (no complicated calculations). Reading from a property implies "nothing will change". Properties are independent of other each other in most cases.

With an accessor method, as opposed to a property, there is the implication of "invoker beware" — more powerful but requiring greater understanding to ensure that the method will succeed.

NSArray or NSSet, NSDictionary or NSMapTable

Some types of data can be held in more than one kind of collection. Unordered objects that are already guaranteed unique can be sensibly held in an NSArray or an NSSet. Anything an NSDictionary can hold can be held in an NSMapTable. In this post, I measure the performance of creating and using these different options to help you choose which one is right for you.


A few weeks ago, I wrote about how NSMapTable and NSDictionary can hold different types of data in different ways. Someone immediately asked: "Which is faster when holding the same data?" I could guess but I didn't really know.

Then I starting thinking about other collections choices which may be ambiguous. I realised that I was writing code that holds a collection of guaranteed unique, unordered objects — just so that I could iterate over them. I used an NSSet for the purpose (since that class defines "unique and unordered") but since the objects were already guaranteed unique before I created the set, I wondered: how much more efficient would my code be if I used an NSArray instead?

So there are two situations to test for performance:

  • NSArray versus NSSet
  • NSDictionary versus NSMapTable

Remember that these tests will only apply to situations where either collection is technically capable of holding the same data.


You can download the code I used for the tests.

To summarise, I create two arrays of data:

  • the "keys" — an array of NSString where each string is a 10 digit string containing being a string representation of its index.
  • the "objects" — an array of NSNumbers where each number is an integer set to its index.

I tested with one million objects in each of these arrays (n = 1,000,000).

The arrays were in turn used to provide the data for the collections that I would test. The one column collections (NSArray and NSSet) are created and tested with objects from the "objects" source array only. The two column collections (NSMapTable and NSDictionary) created and tested with objects from the "keys" and objects" source arrays.

My test machine was a PPC G5 2x2Ghz. Long live dying platforms!


NSArray versus NSSet
TestTime taken for NSArrayTime taken for NSSet
Creating incrementally (capacity not set)0.582256 seconds2.67101 seconds
Creating incrementally (capacity set correctly)0.572139 seconds0.930725 seconds
Iterating contents0.004713 seconds0.025864 seconds

Incidentally, constructing an NSSet using setWithArray: takes the same time as the "capacity not set", so if you know the objects in the array are unique, it would be best to set the capacity and copy the data yourself.

Lookup in NSArray versus NSSet

Note: these results were generated with n = 10,000

TestTime taken for NSArrayTime taken for NSSet
Searching for all objects29.2667 seconds (indexOfObject:)
0.185051 seconds (indexOfObjectIdenticalTo:)
0.00833601 seconds

These results should not be surprising. This test is included for completeness because both collections are capable of inclusion testing.

Searching an array for an objects works well for n < 100. As you can see, by n = 10,000 the O(n^2) behavior of the NSArray tests (an O(n) lookup times n lookups) makes it a bad choice compared to the O(n) of the NSSet tests (constant time lookup times n lookups). I wasn't going to wait for this test with n = 1,000,000 but I assure you, both NSArray approaches would take an amount of time in the minutes or maybe hours.

NSDictionary versus NSMapTable
TestTime taken for NSDictionaryTime taken for NSMapTable
Construction3.45922 seconds2.32607 seconds
Iterating keys and querying each object0.60859 seconds0.770289 seconds


Yes, NSArray is faster than NSSet for simply holding and iterating. As little as 50% faster for constructing and as much as 500% faster for iterating. Lesson: if you only need to iterate contents, don't use an NSSet.

Of course, if you need to test for inclusion, work hard to avoid NSArray. Even if you need both iteration and inclusion testing, you should probably still choose an NSSet. If you need to keep your collection ordered and also test for inclusion, then you should consider keeping two collections (an NSArray and an NSSet), each containing the same objects.

NSDictionary is slower to construct than NSMapTable — since it needs to copy the key data. It makes up for this by being faster to lookup. Of course, the two have different capabilities so most of the time, this determination should be made on other factors.

String philosophies: char arrays, std::string and NSString

Each of the major C variants on the Mac implement character strings in their own way. It is fairly easy to learn the syntax differences between them but a simple API Reference doesn't explain the reasons for implementations: the different philosophies behind the implementations. In this post, I'll go past the 'How' of string differences and instead explain the 'Why' of differences between the three string implementations.

The differences

In C, char * is just a pointer and requires that you access each character in turn to make any sense of the string. The C Standard Library provides a few functions but very little beyond basic array manipulation.

In C++, std::string is more type-safe, offers bounds checking, plays nicely with input and output streams and provides traversal and extraction functions but otherwise expects that you'll access each character individually, in much the same way as you would for char *.

NSString lives apart from its C-derived bretheren. You may never need to access its characters individually — in fact, direct access to the enclosed storage is forbidden. It is loaded with various processing functions. It also understands its own encoding and can convert itself to others.

Underlying binary representations

Standard C's char arrays

A Standard C string (normally typed as a char *, or char[]) is a series of 8-bit bytes of binary data, starting at an arbitrary memory address and proceeding until a zero byte ('\0') is encountered. You can set a char * to any address in memory and begin treating memory from that point as a string.

If the string is an ASCII string, the highest bit in every byte will be zero, for other representations, there's no guarantee. String length is always a byte-length calculation (that doesn't include the '\0' valued terminating byte), so for any variable length character representations (UTF-8), the length and the number of characters are not guaranteed to be the same thing.

C++'s std::string

The philosophy of C++ is to provide a "limited overhead" addition of object-orientation to Standard C. Following this philosophy, the content of std::string in C++ is binary identical to a char[]. There's normally a capacity, length and possibly vtable value in there but otherwise it's pretty much a Standard C string.

C++ also provides std::wstring which is 16-bits per character (instead of std::string's 8-bits) but is otherwise fairly similar. But despite handling wide characters, std::wstring is still unaware of its encoding, making any encoding conversion, including conversion to std::string entirely the programmer's responsibility.

Objective-C's NSString

Objective-C's NSString (technically, Foundation's but the distinction is blurred in Cocoa) is nothing like the other two. Following the philosophy of a class-cluster, NSString offers no guarantees about how it is represented internally since it may transparently substitute a content-optimised subclass for NSString on construction, choosing to represent its internals in whatever way is most appropriate for the data. Internally, an NSString could be 8-bit, 16-bit or 32-bit values; it could be stored contiguously or in a heap structure for mutability; although most of the time, it's a contiguous block of 16-bit values.

Accessors to NSString's characters return unichar (16-bit values values), so generally you treat NSString as though it is a contiguous block of unichar values, even though it may not technically be true. Since a few UTF-16 characters actually span multiple unichar the number of fully decoded character sequences is not guaranteed to be the same as the string's length but in non-Latin scripts, the length will generally be closer than either char * or std::string would be.

NSString is encoding aware, meaning that it knows how to convert itself correctly to other encodings. This can be a little annoying for programmers not used to specifying their encodings but makes NSString easily adaptable for display and processing of any language.

Aggregate versus iterative processing

Both C and C++, promote the philosophies of sequential access. If you need to transform or process the a string, you're expected to access each character yourself and perform the work needed.

For example, converting a string to uppercase takes one of the following forms:

int i, length = strlen(myString);
for (i = 0; i < length; i++)
    myString[i] = toupper(myString[i]);



Since NSString limits access to its internals, it must provide most function done character by character in C or C++ at the string level. This means that NSString must provide vastly more functions to cover your likely needs but it also makes common tasks really easy:

myString = [myString uppercase];

It also has the advantage that these operations can be multi-character sequence aware, unlike the character operators in C and C++ which only act on single characters.

Objective-C's philosophy of aggregate processing goes further than this. NSString methods such as pathComponents and componentsSeparatedByString: provide the means to extract multiple objects in one pass — something that C and C++ never do in their standard libraries. Methods like rangeOfCharacterFromSet: allow aggregate testing — testing multiple characters against the string in a single instruction.

A final aspect of NSString's design philosophy is that it is intended to be used as a class in a modern operating system. This is shown through the method stringByResolvingSymlinksInPath. This task, while common on Unix derived operating systems, would be pointless in many of the environments in which pure C runs. It also shows NSString's willingness to adapt itself towards one of its common uses, something which the C++ Standard Libraries avoid.


C is often described as the programming language which most closely models a general abstract CPU. It is tiny and light, providing the programmer with little more than basic arithmetic, memory access and input/ouput primitives to do their work. C's small size has allowed it to be ported to practically every CPU and environment in existence. Its closeness to an abstracted CPU also means that, if used correctly, it is as fast and optimal as a compiled language can be.

C++ adds a whole host of object paradigms and an extended standard library to the underlying syntax of C. Where possible, C++ tries to be a "zero cost" addition to C. In reality, this amounts to "limited overhead" but with understanding, C++ still allows precise C-level control. The C++ libraries focus on templating, with the premise that the choice of template variable should determine the scope, not the available methods.

From a compiler perspective, Objective-C is more C-like than C++. Philosophically speaking though, it's truly the odd one out. It provides proper unicode string handling. It provides large amounts of processing options, outputs arrays and provides specialized methods for the most common tasks. It doesn't reveal details about how it is stored internally but uses this to provide significant optimizations solutions where possible.