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

Adapter interfaces in Objective-C, using categories.

The Categories feature of Objective-C lets the programmer add extra sets of methods after compilation, something impossible in most compiled languages. Using this feature, here is an Objective-C variant of the classic "Adapter" design pattern that allows two classes to work closely together, without two-way coupling dependency problems.

Connecting two classes: the simple version

This article is about making two (or more) classes work together. The traditional way that happens is like this:

  1. Implement "Class A" with a given set of methods
  2. Implement 'Class B', invoking methods that 'Class A' already provides

Obviously, this is how almost all class interaction works. And it works well, especially in situations where "Class B" is dependent on "Class A" but "Class A" remains independent.

Working closely together works badly

When both classes need to work closely together, keeping their interfaces and operation clean and clear becomes difficult.

What can we do when the second class needs information that the first class doesn't provide?

We could keep adding methods to "Class A" to give "Class B" everything it needs but coupling two classes together (by adding extra design features to one purely for the other to use) is generally considered bad for maintenance reasons.

If the extra methods are useful in a more general sense, then this isn't a problem but if these extra methods are only useful for "Class B", then we are really breaking the abstraction between the two classes because the "Class A" now knows everything that "Class B" needs internally. Non-hierarchic coupling of classes is normally considered an "anti-pattern" (bad design choice) for this reason.

How do we neatly perform a calculation that needs parts inside each class?

If we are performing an aggregate calculation where parts of the calculation need to be performed inside each of the two classes, then the algorithm may be difficult to read and maintain because it is split across multiple modules.

We could create a third class or module to perform the calculation in a unified place but that may generate the same coupling issues described in the previous section, where the third class now needs specifically tailored interfaces into "Class A" and "Class B" in order to access the data it needs to perform its work.

A solution using categories

Most of the time, categories in Objective-C are used to define extra methods for a class in a separate library — where the original set of methods on a class can't be changed. Categories can also be used to break up a class according to areas of concern. This is how we will use it in this solution: breaking coupling issues between classes by dividing the classes up according to their areas of concern.

Our problem consists of these constraints:

  1. "Class B" needs some detailed information from "Class A"
  2. It's not really "Class A"'s job to care about what "Class B" is doing.

We can solve this problem by creating extra "Class A" methods inside "Class B"'s source file. Specifically, we create a category of "Class A" inside the source file for "Class B".

This allows the source file for "Class A" to remain independent of "Class B", yet still allows "Class B" to obtain specially catered information. The result is that the methods in the source file for "Class A" are those public "Class A" methods that any class may use, whereas "Class B" defines its own private interface — so private that the base "Class A" definition remains unaware of it. It also allows a calculation which may be split across both classes to be performed entirely in one source file, for neatness and clarity.

The "Adapter" interface described in the article title refers to the "Adapter" design pattern. Normally, an Adapter is a third class written for the purposes of linking two incompatible classes. In this case, Objective-C's categories let us create the Adapter inteface as an extension of "Class A" but residing inside the implementation file for "Class B".

Summary

The Adapter interface is structured as follows.

Class A's implementation:

@implementation Class_A
// Class_A's methods
@end

Class_B's implementation:

@ implementation Class_A (Class_B_Adapter)
// Methods to allow Class_B to connect to Class_A
// Methods that Class_B can use to calculate values dependent on both Class_A
//   and Class_B
@end

@ implementation Class_B
// Class_B's methods
@end

Note that these are the "implementation" files, not the "interface" files. Since this is a private interface for "Class B" to interact with "Class A", the "Class_A (ClassBAdapter)" should not appear in the interface file.

This type of design allows "Class B" to work closely with "Class A" without forcing the default implementation of "Class A" to change just to suit "Class B" and further allows the implementation of the "ClassBAdapter" methods to live close to their usage.

Implementing countByEnumeratingWithState:objects:count:

If you want to use fast enumeration on your own classes, you must implement countByEnumeratingWithState:objects:count:. Unfortunately, it's a confusing method. Here are two sample implementations that show the steps needed to implement this method in most cases.

Some sample NSFastEnumeration implementations

You need to implement NSFastEnumeration if you want to use your own classes in the Objective-C 2.0 "for...in" fast-enumeration language feature.

The documentation for its only method (countByEnumeratingWithState:objects:count:) is pretty cryptic and overwhelming — mostly because the method needs to be flexible and Apple don't want to tell you how to write your code. I have no such qualms and since there aren't many examples on the Internets at the moment I thought I'd show you some easy approaches for implementing it in your own programs.

There are two different ways to enumerate. The first is where your class already has, or is willing to create, a C array of Objective-C id values which point to the objects being enumerated. The second is where you don't have this storage and want to use storage passed to you.

Warning: These examples do not use the mutationsPtr and are therefore only safe for use with immutable collections. If the enumerated collection is mutable, you will need to point mutationsPtr to an appropriate mutation guard value (normally a mutations count value).

First case: already have a C array of storage

Our class looks like this:

@interface SimpleStringArray : NSObject <NSFastEnumeration>
{
    NSString *stringArray[ARRAY_LENGTH];
}

In this case, the implementation of countByEnumeratingWithState:objects:count: would look like this:

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
{
    if (state->state >= ARRAY_LENGTH)
    {
        return 0;
    }

    state->itemsPtr = stringArray;
    state->state = ARRAY_LENGTH;
    state->mutationsPtr = (unsigned long *)self;
    
    return ARRAY_LENGTH;
}

Quick explanation:

  • we've ignored stackbuf and count (because we already have storage)
  • as required, we've set state->state to a non zero value (the iteration index after the current items are iterated)
  • as required, we've set state->mutationsPtr to a non zero value (the self pointer since we have no "array has changed" flag that we can point it to)
  • we've returned the complete length of the array, so it will all be iterated in one pass (on the second pass, state->state will equal ARRAY_LENGTH and we'll return "0", ending the loop)

Second case: need storage

If our class' data is a collection of NSString objects stored in a list of linearly connected C structs, then we might have no C array value to return.

Assume our list is declared like this:

typedef struct
{
    NSString * stringPtr;
    struct MyList * nextNode;
} MyList;

and our class is declared like this:

@interface StringList : NSObject <NSFastEnumeration>
{
    MyList * _startOfListNode;
    MyList * _endOfListPlusOneNode;
}

This is more complicated example because we need to actually gather the data from the list and store our traversal state between iterations. Here is how it might look:

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
{
    MyList *currentNode;
    if (state->state == 0)
    {
        // Set the starting point. _startOfListNode is assumed to be our
        // object's instance variable that points to the start of the list.
        currentNode = _startOfListNode;
    }
    else
    {
        // Subsequent iterations, get the current progress out of state->state
        currentNode = (struct MyList *)state->state;
    }
    
    // Accumulate nodes from the list until we reach the object's
    // _endOfListPlusOneNode
    NSUInteger batchCount = 0;
    while (currentNode != _endOfListPlusOneNode && batchCount < len)
    {
        stackbuf[batchCount] = currentNode->stringPtr;
        currentNode = currentNode->nextNode;
        batchCount++;
    }

    state->state = (unsigned long)currentNode;
    state->itemsPtr = stackbuf;
    state->mutationsPtr = (unsigned long *)self;

    return batchCount;
}

Explanation of this example:

  • We now use stackbuf to store the data accumulated from the list and we return it in state->itemsPtr.
  • len is used now because it is the maximum number of objects we can accumulate in stackbuf each time.
  • When executed the first time (when state->state == 0), we set the currentNode to our object's private _startOfListNode — that we assume we have correctly set to the start of our list.
  • Every other time we are run, state->state will hold our currentNode, saved from the last iteration.
  • The fast enumeration will repeatedly invoke this method until we reach a currentNode == _endOfListPlusOneNode at the end of the list — remember that state->state is not allowed to be nil, which is why we use this non-nil end marker node. If you use a list that ends in nil, then you should detect this and set state->state to a special non-nil "end" flag so that you won't get trapped in an infinite loop.

Objective-C 2.0: Fast enumeration clarifications

Fast enumeration in Objective-C 2.0 is a doubly useful addition: it results in code that looks better and runs faster. Its documentation though, still contains a few points which are ambiguous or misleading. Here are some clarifications that I've uncovered.

Things you should already know

In case you've never heard of it, fast enumeration is an addition in Objective-C 2.0 which allows you to turn an Objective-C 1.0 NSSet (or other collection) enumeration from:

NSSet *objectSet = <#setaccess#>;
NSEnumerator *enumerator = [objectSet objectEnumerator];
id setObject;
while ((setObject = [enumerator nextObject]) != nil)
{
    <#!loopcontents#>
}

to:

for (id setObject in <#setaccess#>)
{
    <#!loopcontents#>
}

Your code will also run faster because the internal implementation reduces message send overhead and increases pipelining potential.

The resulting syntax is more aesthetic and better reflects the programmer's intent. Faster and better looking, it's like a sports car for nerds (without the higher sticker price or jokes about mid-life crises).

Documentation Clarifications

How do you enumerate backwards? Or enumerate dictionary objects instead of keys?

Apple have noted throughout the Cocoa documentation that you can use Fast Enumeration instead of NSEnumerator in Mac OS X 10.5. In the documentation for -[NSArray reverseObjectEnumerator] they have stated: "On Mac OS X v10.5 and later, it is more efficient to use the fast enumeration protocol".

This statement may seem a little puzzling, since Fast Enumeration does not let you choose the enumeration direction. What Apple mean in this case though, is that you can use the reverse NSEnumerator object itself for Fast Enumeration. Just get the reverse object enumerator and pass it in as though it were the collection.

Like this:

for (id object in [someArray reverseObjectEnumerator])

The latest downloadable XCode Documentation Set still omits the fact that NSEnumerator actually implements NSFastEnumeration. The documentation for NSEnumerator at developer.apple.com has finally fixed this omission and it is in the Mac OS X 10.5 header files, so the above code is actually valid syntax.

This will then work for any NSEnumerator returning method, including NSDictionary's objectEnumerator.

Will the "collection" expression code be invoked each time?

In the above case, you may wonder if -[NSArray reverseObjectEnumerator] would be run on every iteration of the loop — potentially slowing down the code. Not very serious in this case but what if your code looked like this:

for (id object in [someObject generateArrayInTimeConsumingCode])

In a normal C for loop, you would expect the for expression to be evaluated on every iteration. The Objective-C 2.0 Programming Language: Fast Enumeration page implies that it would be evaluated on every invocation of countByEnumeratingWithState:objects:count: (every handful of iterations).

By using a test class that implements its own countByEnumeratingWithState:objects:count:, I was able to determine that neither is the case. The "collection" expression is only evaluated once, when the for loop begins. This is the best case, since you can safely put an expensive function in the "collection" expression without impacting upon the per-iteration performance of the loop.

Must the data returned be object pointers ("id"s)?

No. The compiler generates no code that reads from the data returned, so it doesn't care.

Even though the pointer to enumeration data is declared as:

id *itemsPtr;

you can return an array of any data you want, provided it is contained in a pointer-sized array. For example, pointers to structs is okay, as are char values (provided they are spaced sizeof(id) apart).

What happens to Fast Enumeration code in 10.4?

The documentation clearly states that Fast Enumeration will not work in Mac OS X 10.4 and the compiler will give you warnings if you try to compile it.

But that's not completely true.

If you compile against the Mac OS X 10.5 SDK libraries but set your minimum required OS to Mac OS X 10.4, you will get warnings that "for...in" constructs aren't supported. Within certain bounds though, you can ignore these warnings.

For Fast Enumeration of your own classes, "for...in" constructs will work under 10.4 without modification.

Two potentially serious issues exist with attempting to run Fast Enumeration code under 10.4:

  • None of the Cocoa classes in Mac OS X 10.4 implement the NSFastEnumeration protocol, so you would need to dynamically load countByEnumeratingWithState:objects:count: methods of your own design into them at runtime when running under Mac OS X 10.4.
  • The objc_enumerationMutation function doesn't exist under 10.4, so if you mutate a collection while iterating, you won't throw an exception, you'll crash.

Obviously, you shouldn't do it unless you have a strong compelling case but the option is there if you're prepared to shoulder the extra effort.

Square Root: Numerical fun with NSDecimalNumber

NSDecimalNumber is a powerful Foundation class that holds high precision base 10 numbers. The default class only provides basic arithmetic operators, leaving you to write any advanced operations that you need. This is an example that implements a square root using NSDecimalNumber.

Casus belli: I want to expand my territory

Do you ever find yourself wishing for greater than the 15 decimal place precision of a 64-bit IEEE 754 floating point number? Of course you do. Your lab equipment is accurate to supernatural levels and your finances regularly deal with tens of trillions of dollars/euros accurately to the cent.

Or perhaps you're more like me — your lab equipment gives answers in "warmer/colder" and your finances are mostly organised around the barter system — but you really like long numbers.

Cocoa proudly offers the Foundation class NSDecimalNumber to satisfy this desire. NSDecimalNumber is a class which will give slightly better than twice the precision of a double (as much as 38 digits) and should never give the weird binary to decimal conversion quirks that binary doubles give (like 0.1 becoming 0.10000000000000000555 without warning).

Sadly, NSDecimalNumber does not appear to be written for the mathematically or scientifically inclined. Its operators are mostly limited to basic arithmetic: add, subtract, multiply and divide. It does provide the ability to raise to a power but only to whole number exponents.

So if we want anything more, we must write it ourselves. No problem?

How do other people implement a square root?

You can't get very far in scientific or statistical calculations without a square root, so it's a good "higher level" function to implement first. So, how is it done?

The short answer is normally "an optimised Newton's method iteration". Newton's method goes like this:

  • Take a first guess at the square root (it will be somewhere between the operand and 1)
  • Use the slope of the line at the guess point (d/dx of sqrt(x) is 0.5x) to choose a next guess
  • Repeat until you're close enough

Within this fairly simple set of steps is a huge range of possible implementation approaches. Most center on choosing a best first guess, avoiding accumulated error, avoiding floating point division and handling convergence quirks around x=1. Professor W. Kahan (who helped invent the IEEE 754 standard) and K.C. Ng wrote a 1986 paper on a range of these different approaches.

Beyond these, there are some very strange alternate implementations of square root, including the "Quake III" square root which contains the utterly baffling line:

i  = 0x5f3759df - ( i >> 1 );

which exploits the specific binary representation of a 32-bit float to choose an exceptionally good first guess.

How will I implement a square root?

I'm going to implement a square root in NSDecimalNumber, without peeking illegally at the internals of the number format (I'm guessing it's just a binary coded decimal). I'm not going to try anything fancy so this implementation will be:

  • a little slow (maybe a hundred microseconds per calculation)
  • may suffer from convergence and rounding errors near x=1 (last 1-3 digits of transcendental results will occasionally be wrong)

At least the code will be simple.

Basic solution

Taking the easiest first guess (an average of the operand and 1) applying Newton's method to solve for the square root looks like this:

- (NSDecimalNumber *)sqrt
{
    NSDecimalNumber *half =
        [NSDecimalNumber decimalNumberWithMantissa:5 exponent:-1 isNegative:NO];
    NSDecimalNumber *guess =
        [[self decimalNumberByAdding:[NSDecimalNumber one]]
            decimalNumberByMultiplyingBy:half];
    
    NSCompareResult compare;
    do
    {
        NSDecimalNumber *previousGuess = [[guess copy] autorelease];
        guess = [self decimalNumberByDividingBy:previousGuess];
        guess = [guess decimalNumberByAdding:previousGuess];
        guess = [guess decimalNumberByDividingBy:two];
        
        compare = [guess compare:previousGuess];
    }
    while (guess != NSOrderedSame);
    
    return guess;
}

Make this a category method of NSDecimalNumber and you'll immediately be able to calculate the square root of 2.

But you'll get weird failures and infinite loops if you try to calculate the square root of 1.01, 0 or anything negative.

A few special cases

Since we're not going to handle imaginary numbers, all attempts to take the square root of a negative number should return [NSDecimalNumber notANumber].

Then we have the quirks associated with taking the square root of zero. Two problems are occurring: if "previousGuess" is zero, then we are creating a divide by zero exception. Secondly, we are deliberately trying to converge on zero as the solution which means that we are deliberately creating an "underflow" (which is another kind of exception in NSDecimalNumber).

To address these problems, we'll simply put a blanket "try/catch" block around the do/while loop. When an exception occurs, we'll simply return the current guess which we can safely assume to be correct in both these cases.

Then we are left with one final problem: the listed method iterates until it converges on a solution (the guess has the same value for two iterations in a row). Unfortunately, there are many cases where this will never occur — especially for values close to 1. Instead, we'll replace the do/while with a fixed number of iterations. Experimentally, 4 iterations seems to handle most situations, 5 is sometimes needed. I've gone with 6 to be safe.

Unanswered question

This solution will give square root answers with a worst case accuracy of 34 decimal places for values near 1 (according to my few experiments). I was expecting a worst case of at least 36 decimal places so I'm a little confused.

This error does not appear to be due to accumulated error or convergence problems. It appears to be because NSDecimalNumber is rounding numbers like (1 + 1e-35) to the nearest integer — even when I use an NSDecimalNumberBehaviors object that returns NSDecimalNoScale. This would appear to be unnecessary, given the 38 digit length of the mantissa. I'm not quite certain why it would do this but it appears to be reducing accuracy by approximately 2 decimal places.

If you know why this may be happening, please leave a comment and let me know.

Final solution

- (NSDecimalNumber *)sqrt
{
    if ([self compare:[NSDecimalNumber zero]] == NSOrderedAscending)
    {
        return [NSDecimalNumber notANumber];
    }
    
    NSDecimalNumber *half =
        [NSDecimalNumber decimalNumberWithMantissa:5 exponent:-1 isNegative:NO];
    NSDecimalNumber *guess =
        [[self decimalNumberByAdding:[NSDecimalNumber one]]
            decimalNumberByMultiplyingBy:half];
    
    @try
    {
        const int NUM_ITERATIONS_TO_CONVERGENCE = 6;
        for (int i = 0; i < NUM_ITERATIONS_TO_CONVERGENCE; i++)
        {
            guess =
                [[[self decimalNumberByDividingBy:guess]
                    decimalNumberByAdding:guess]
                        decimalNumberByMultiplyingBy:half];
        }
    }
    @catch (NSException *exception)
    {
        // deliberately ignore exception and assume the last guess is good enough
    }
    
    return guess;
}

Open the previous document on application startup

Setting up your application to open the most recent document on startup is easier than you might think. Here's a quick solution with a some code you can plug straight into your app.

Recent instead of Untitled

If the user is likely to edit the same document over multiple sessions of the application, automatically opening the last edited document when your app starts up is a helpful option to offer.

To make this easier for us, Mac OS X automatically remembers the last ten documents opened.

We are left with three steps to make this happen:

  • Prevent the default "Untitled" document opening
  • Open the most recent document as reported by the shared NSDocumentController
  • Allow "Untitled" documents to open after startup

All in the application delegate

The application's delegate is the appropriate place to do this work, most of which will occur in the delegate method applicationShouldOpenUntitledFile:.

Normally, this method returns YES. Even if we want the most recent document to open at startup, we will want this method to return YES after startup.

But we can't directly ask NSApplication if it is starting up, so we must keep a flag applicationHasStarted that should be initialized to NO in the delegate's constructor and set to YES in applicationDidFinishLaunching:. In the code example below, I assume you've already set up this behavior and I don't show it explicitly.

So, inside the body of applicationShouldOpenUntitledFile:, if applicationHasStarted is NO, we ask the shared NSDocumentController for the most recent document, get the URL of this document and open it, returning NO from applicationShouldOpenUntitledFile: to prevent the untitled document appearing.

Solution

- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
{
    // On startup, when asked to open an untitled file, open the last opened
    // file instead
    if (!applicationHasStarted)
    {
        // Get the recent documents
        NSDocumentController *controller =
            [NSDocumentController sharedDocumentController];
        NSArray *documents = [controller recentDocumentURLs];
        
        // If there is a recent document, try to open it.
        if ([documents count] > 0)
        {
            NSError *error = nil;
            [controller
                openDocumentWithContentsOfURL:[documents objectAtIndex:0]
                display:YES error:&error];
            
            // If there was no error, then prevent untitled from appearing.
            if (error == nil)
            {
                return NO;
            }
        }
    }
    
    return YES;
}