Cocoa with Love

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

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 newest XCode Documentation Set still omits the fact that NSEnumerator 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.

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 it can work.

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.

Read more...

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;
}
Read more...

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;
}
Read more...

Propagate deletes immediately in Core Data

Learn some limitations associated with cascading deletes in Core Data and find out how to immediately propagate deletes in Core Data, overcoming these potential problems.

Correction: this post previously indicated that NSManagedObject deletes would fail inside processPendingChanges. This issue was fixed in Mac OS X 10.5. The post has been edited to reflect that in Mac OS X 10.5 it is only processPendingChanges that cannot be invoked inside itself.

Limitations to the default "deleteObject" for change propagation

Core Data has the ability to perform full object-graph deletes through the "cascade" delete rule available to each entity in the object model.

If you have overridden the Key Value Coding methods for relationships on your model entities you can encounter the following issues.

Always deferred

Deletes in Core Data are always deferred, either to the end of the event (when -[NSManagedObjectContext processPendingChanges] is next called) or until the context is saved.

This means that if you want to read a value changed by a delete, you must:

  • not be inside a -[NSManagedObjectContext processPendingChanges] invocation (i.e. during a delete propagation)
  • call -[NSManagedObjectContext processPendingChanges] after the delete to flush the work through

If you are inside processPendingChanges (or you otherwise don't want to call it) but you need to see changes immediately, then you will need to implement your own change propagation instead of relying on the default deleteObject: to apply changes.

Relationships deleted in no particular order

The "cascade" Delete Rule does not cascade through relationships in any particular order. If you need relationships to be deleted in a specific order (i.e. if you may read from the object during deletion), you will need to implement your own change propagation.

No recursive deletes in 10.4

In Mac OS X 10.4, Core Data's delete propagation is incompatible with recursively invoked deletes. If a delete propagation triggers another delete propagation while it is doing its work, the second propagation won't work (it will have no effect).

An example of how these problems can occur

Consider the following .xcdatamodel:

In this example, "A" uses a "cascade" Delete Rule for its properties but "B" and "C" use "nullify".

Our program must obey the following rule:

    Every B object attached to an A object must have a matching C object attached to the same A object at all times.

Our program maintains this rule by overriding the Key Value Coding methods for the "A" class.

The addBObject: method is overridden to create a C object and add it to the "A" object's "c" property before the "b" property is changed. Similarly, the removeBObject: method is overridden to delete the matching C object in the "A" object's "c" property after the "b" property is changed.

By adding the "C" object before the "b" property is changed and removing the "C" object after the "b" property is changed, we ensure that while a "B" object is attached to an "A" object, there is always a matching "C" object attached.

Once we've deleted the "C" object, we use NSAssert to check that the number of "B" objects and "C" objects attached to "A" are the same. To ensure that the "C" object has been deleted before this read, we must call processPendingChanges to flush through the delete.

Problems with nested processPendingChanges

The above described example will work fine, unless it is invoked from inside a delete propagation.

If we delete a "B" object, instead of simply removing it from "A", then the removal happens inside the processPendingChanges for the "B" object's delete.

In Mac OS X 10.4, the deleteObject: invocation in removeBObject: will not work correctly from inside processPendingChanges. This is a documented limitation. Any use of deleteObject: in an overridden accessor in Mac OS X 10.4 should propagate deletes itself.

In Mac OS X 10.5, the call to processPendingChanges in removeBObject: will have no effect. This means that the NSAssert will fail.

In this trivial example, the NSAssert isn't important but it shows that if you need to flush deletes to read back immediately and may need this functionality during a delete propagation, then you will need to propagate this delete yourself.

Problems with order of delete

If you delete an "A" object, then you have no control over whether the "b" property or "c" property is deleted first.

The "C" property could be deleted first. If this occurs, then the rule "must have a matching C object attached to the same A object at all times" is violated.

If you need control over the order that relationships are deleted, then you must propagate the delete yourself.

Solution: actively perform the delete propagation yourself

A solution to the above listed problems is to actively perform the delete propagation yourself. This means iterating over all relationships on the object and using the deleteRule information from the relationship to decide how to handle the object on the other end.

This is going to be slower than the default delete propagation but we are deliberately replicating its behavior so that we can have greater control over what is done during the propagation.

Objects will still be deleted using -[NSMangedObjectContext deleteObject:] but before this occurs, they will be correctly disconnected from the object graph. To ensure that no infinite loops occur, all relationships in affected objects are set to nil as propagation passes through.

A brief warning: the following method doesn't handle the "Deny" delete rule. You would need to add support for this yourself.

So here's the big block of code. This is intended to be a Category method on NSManagedObject (otherwise it won't work as written). The priorityDeletionRelationships method should be overridden by classes which need some relationships deleted first — the array returned should be the ordered list of relationship keys to delete first.

- (NSArray *)priorityDeletionRelationships
{
   return nil;
}

- (void)propagateDelete
{
   NSEntityDescription *entityDescription = [self entity];
  
   // Get the set of relationships
   NSDictionary *relationships = [entityDescription relationshipsByName];
   NSArray *unsortedKeys = [relationships allKeys];
   NSArray *priorityKeys = [self priorityDeletionRelationships];
   NSArray *keys;
   if ([priorityKeys count] > 0)
   {
       keys = [[unsortedKeys mutableCopy] autorelease];
       [(NSMutableArray *)keys
           removeObjectsInArray:priorityKeys];
       [(NSMutableArray *)keys
           replaceObjectsInRange:NSMakeRange(0, 0)
           withObjectsFromArray:priorityKeys];
   }
   else
   {
       keys = unsortedKeys;
   }
  
   // Iterate over the set of relationships
   NSEnumerator *relationshipEnumerator = [keys keyEnumerator];
   NSString *relationshipName;
   while ((relationshipName = [relationshipEnumerator nextObject]) != nil)
   {
       NSRelationshipDescription *relationshipDescription =
           [relationships objectForKey:relationshipName];
      
       // If the relationship is not "cascade", then just nullify it.
       if ([relationshipDescription deleteRule] != NSCascadeDeleteRule)
       {
           if (![relationshipDescription isToMany])
           {
               [self setValue:nil forKey:relationshipName];
           }
           else
           {
               NSMutableSet *relationshipSet =
                   [self mutableSetValueForKey:relationshipName];
               [relationshipSet removeAllObjects];
           }
           continue;
       }
      
       // Propagate the delete to the object at the other end of the
       // relationship
       if (![relationshipDescription isToMany])
       {
           NSManagedObject *destination = [self valueForKey:relationshipName];
           [self setValue:nil forKey:relationshipName];
           [destination propagateDelete];
           continue;
       }
      
       // Propagate the delete to every object in the to-many relationship.
       // We copy the set because we plan to change it during iteration.
       NSMutableSet *mutableRelationship =
           [self mutableSetValueForKey:relationshipName];
       NSSet *iterateSet = [[mutableRelationship copy] autorelease];
       NSEnumerator *enumerator = [iterateSet objectEnumerator];
       NSManagedObject *setObject;
       while ((setObject = [enumerator nextObject]) != nil)
       {
           [mutableRelationship removeObject:setObject];
           [setObject propagateDelete];
       }
   }
  
   // Delete this object
   [[self managedObjectContext] deleteObject:self];

}
Read more...

viewWillDraw - a welcome addition to NSView in 10.5

A method named viewWillDraw appeared in NSView in Mac OS X 10.5. If you have cause to use it, this method replaces 6 other methods from earlier versions of Mac OS X. Read more to find out if you should use it and how it helps.

Drawing in NSView

Drawing in Cocoa happens in the NSView method drawRect:. Almost all programs perform some form of custom drawing, so this is one of the most commonly overridden methods in Cocoa.

The general procedure to follow in this method is:

  • Determine what needs to be drawn
  • For each component that needs to be drawn, draw the component

But what happens if, in the course of determining what needs to be drawn, you need to alter the area being updated? If, after determining what needs to be drawn, we realize that a different region needs to be updated, it's too late — the drawing rectangle can't be changed from inside drawRect:.

Layout code

The above described problem is exactly what is faced by deferred or pending layout code.

Layout code deferred until drawInRect: is unable to change the bounds for drawing and must a separate drawRect: invocation. This can create pauses in display, tearing or other drawing problems.

Let me be clear here: when I say "layout", I don't mean the arrangement of NSViews in a window (these will handle themselves). "Layout" in this sense means graphical objects within a single view which may need to be arranged in some way (i.e. column alignment, animation or other procedural generation or positioning).

Deferred layout isn't very common (since drawing is normally triggered after layout is performed) but there may be cases where drawing begins while layout updates are still pending and you want to block the current drawRect: invocation until the layout update is complete. If those layout updates alter the bounds of objects being drawn, we'll want the current invocation of -[NSView drawRect:] to update those bounds, to avoid drawing glitches.

The old solution

The solution to this problem is to perform the layout required for drawing slightly earlier than drawRect: — before the NSView is locked into drawing a fixed rectangle. This gets around the limitation that drawRect: can only update the area it is given.

Previously, this meant performing pending layout in these NSView methods:

  • displayIfNeeded
  • displayIfNeededIgnoringOpacity
  • _recursiveDisplayAllDirtyWithLockFocus:visRect:
  • _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:
  • _recursiveDisplayRectIfNeededIgnoringOpacity:inContext:topView:
  • _lightWeightRecursiveDisplayInRect

These are all the immediate predecessor methods to drawRect:. When these methods are invoked, it is early enough to extend the drawing region by invoking setNeedsDisplayInRect: and the new drawing region will get included when drawRect: is invoked.

Unfortunately, only the first two other these methods are documented. The remainder are undocumented and Apple is free to change them without notice — potentially messing up your program. So "the old solution" was not a good solution.

Conclusion: the Leopard solution

Fortunately, Mac OS X 10.5 gives a much cleaner function to override before drawRect: is invoked &mdash viewWillDraw. This method is the perfect spot to perform deferred or pending layout. You can alter the bounds that need to be updated and this new altered region will be included on the very next update. This means no tearing and no holes in your drawing.

Read more...

Type punning isn't funny: Using pointers to recast in C is bad.

A very common C technique for reinterpreting data types has the potential to cause nasty bugs. Apple knows this, which is why the implementation of NSRectToCGRect (correctly) doesn't do what the documention claims. I show you a technique to perform reinterpret casts safely in your own code.

Apple's documentation for the function NSRectToCGRect claim that it is implemented as follows:

CGRect NSRectToCGRect(NSRect nsrect) {
   return (*(CGRect *)&(nsrect));
}

If you have seen a lot of C code, chances are that you've seen this approach before. You can't cast one struct to another to reinterpret — even if they have the same fields — so it is common to see reinterpreting by making a pointer and casting the pointer.

The implication is that NSRectToCGRect reinterprets an NSRect as a CGRect without altering the contained data.

While the implied functionality is accurate, the displayed implementation is not. In actuality, the function looks like this:

NS_INLINE CGRect NSRectToCGRect(NSRect nsrect) {
    union _ {NSRect ns; CGRect cg;};
    return ((union _ *)&nsrect)->cg;
}

Why the difference? Why bother creating a union? Why shouldn't you simply cast through a pointer?

Type punning

As common as casting through a pointer is, it is actually bad practice and potentially risky code. Casting through a pointer has the potential to create bugs because of type punning.

Type punning
A form of pointer aliasing where two pointers and refer to the same location in memory but represent that location as different types. The compiler will treat both "puns" as unrelated pointers. Type punning has the potential to cause dependency problems for any data accessed through both pointers.

Most of the time, type punning won't cause any problems. It is considered undefined behavior by the C standard but will usually do the work you expect.

That is unless you're trying to squeeze more performance out of your code through optimizations. Specifically, if you ever turn on "Enforce Strict Aliasing" in XCode (a.k.a -fstrict_aliasing in GCC) you run the risk of unpredictable and errant behavior. With strict aliasing, the compiler may start doing things in the wrong order or leaving instructions out entirely.

To be clear, these bugs can only occur if you dereference both pointers (or otherwise access their shared data) within a single scope or function. Just creating a pointer should be safe.

An example of a punning bug

Before the NSRectToCGRect function existed, I had some code which did the following:

NSRect ellipseBounds;
ellipseBounds.origin.x = 0;
ellipseBounds.origin.y = 0;
ellipseBounds.size.width = WIDGET_SIZE - 1.0;
ellipseBounds.size.height = WIDGET_SIZE - 1.0;
ellipseBounds = NSInsetRect(ellipseBounds, 4, 4);

CGContextAddEllipseInRect(context, *(CGRect *)&ellipseBounds);
CGContextFillPath(context);

This code creates and sets up an NSRect and then reinterprets it as a CGRect before using it.

In this case, with -fstrict_aliasing enabled, GCC chose to order the NSInsetRect after the call to CGContextAddEllipseInRect because the dependency between the two was broken by type punning when the pointer to ellipseBounds was dereferenced as a different type.

Union solves the problem

The traditional solution to this problem, to allow the code to be correct with -fstrict_aliasing enabled, is to use a union. As shown in the NSRectToCGRect code, the union should contain the source and destination types and you simply set or cast to the source type before reading from the destination type.

According to the C standard, anything involving type punning is implementation specific. So in a "standard" sense, using a union doesn't necessarily solve the problem. According to the standard, if you set data in a union on one field, you are required to read back from the same field.

Fortunately, GCC explicitly gives permission to do different. From the GCC documentation:

The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type.

Excellent.

A macro to reinterpret your own data safely

Really simple:

#define UNION_CAST(x, sourceType, destType) \
	(((union {sourceType a; destType b;})x).b)

So you could cast a float variable named myFloat to an int as follows:

int myInt = UNION_CAST(myFloat, float, int);

You might notice that I don't bother with an inline function, I don't give the union a name, and I don't make a pointer to the value before casting. The Apple NSRectToCGRect function did these things but they are unnecessary. Although, since the compiler should optimize away the extra work, the function, the extra pointer and the dereference in Apple's code shouldn't matter.

Conclusion

Creating a pointer to a value and recasting the pointer to a new type is the most common way to reinterpret data in C that I've seen. Despite its prevalence, you shouldn't do it. Always do your reinterpret casts through a union. It could save you a lot of trouble if you're ever trying to squeeze performance through compiler options.

Read more...

The value of immutable values

This is an explanation of why Cocoa contains immutable value classes and why the value classes you create in your own program should be immutable too. This post is brought to you by yet another bug release of Magic Number Machine: v1.0.24

Mea culpa

In 2002, I wrote the BigFloat class that would end up being the floating-point number class in my calculator, Magic Number Machine.

When I wrote this class, I was new to Cocoa programming and didn't really understand some of its design philosophies. Specifically, I didn't understand why Cocoa chooses to store its values in immutable classes.

Without this understanding as I wrote the BigFloat class, I designed the operator methods (add:, subtract:, multiplyBy:, divideBy:) to store their result in the receiving object, thereby changing or "mutating" the receiving object.

For example, in Magic Number Machine's BigFloat class, [a add:b] adds "b" to "a" and stores the result in "a".

Storing the result in the same location as one of the operands is common in assembly language and lots of classes have methods that change the underlying object. But this is the wrong approach for an Objective-C value class.

So let's look at why value objects in Cocoa should be immutable where possible.

Immutable objects in Cocoa

It may be useful to clarify what is meant by "immutable":

Immutable object
In object-oriented and functional programming, an immutable object is an object whose state cannot be modified after it is created. This is in contrast to a mutable object, which can be modified after it is created.
From http://en.wikipedia.org/wiki/Immutable_object

It may sound like immutable classes are worse than mutable classes since they contain less functionality. It may then be surprising how many Cocoa classes are immutable. Immutable classes in Cocoa include:

  • NSValue
  • NSNumber
  • NSURL
  • NSDate
  • NSString
  • NSArray
  • NSColor
  • NSEvent
  • NSFont

The reality is that these classes don't necessarily do less than their mutable equivalent but they do always return changes in a newly allocated object instead of changing themselves.

A further trait in common is that all of these classes can be considered "value" classes. They store an indivisible piece of data which is intended to be read and used in its entirety.

The problem with mutable value objects

Objective-C shared references

In Objective-C, it is common to retain objects returned from other classes. "Get" accessor methods often return objects owned by another object that you are free to retain as though it is your own.

The result is that multiple parent objects often maintain references to the same child object. Even if you're using Garbage Collection and you don't explicitly type "retain", it doesn't matter, the effect is the same: multiple objects have a pointer to the same object.

This leads to the biggest problem with mutable values: if one of the sharing objects changes the value object, then both sharing objects see a changed value. This is fine if the value object is supposed to be a shared state object between the sharing objects but is very bad in all other cases.

To prevent external objects changing your internal state without permission, all internal state should be returned immutable. If no immutable class exists, you will need to copy the internal object first and return the copy.

Threading concerns

Multiple objects sharing references to the same data can also create race conditions in threaded code.

Immutable objects largely avoid race conditions because one value can be swapped for another atomically.

Consecutive Use

Another problem with mutable values, is that the original value is lost if you don't make a copy before applying an operator.

This causes problems depending on usage pattern. If value objects are ever used in a situation where more than one operator needs to be applied to the original object you must remember to copy the original object before applying an operator.

For example, if you have value X, it is common to want to calculate X + Y and X + Z. In a mutable object world, if calculating X + Y destroys X, then you must pre-copy X so that it still exists when you want to calculate X + Z.

Aesthetic reasons

A final reason to make your value classes immutable is aesthetic.

When writing a description of an operation using mathematical syntax, we write:

result = function(operand1, operand2)

or

result = operand1 operator operand2 

In both cases, the mathematical notation is modelling a case where "operand1" and "operand2" are immutable and a new value "result" is created. To closely reflect this model, "function" and "operator" must act on the operands in an immutable fashion.

When to avoid immutable objects

Any of the following traits can rule out the use of immutable design:

  • Very large data size - since any change to an immutable object requires copying
  • Lazily or progressively constructed data - since immutable objects require all data at construction
  • Classes containing structured data, especially where child elements of the structure are exchanged or manipulated
  • Where a class is intended as a container for shared state

This normally rules out most classes which can't be described as values. For example, you'll never see an immutable application control, view or document state class, like Windows or Views or Documents.

Compound objects like collections (NSArray, NSSet, NSDictionary, etc) regularly exist in both mutable and immutable forms. They are normally mutable when they are progressively constructed, contain large data sets or are used for maintaining shared structural state. But they are often immutable to take advantage of immutable traits (read-only internal access and thread-safe).

Some value objects with large data or structural values (large blocks of text for example) can create gray area where the choice can be hard to make. In the case of text, Cocoa includes the immutable NSString and NSAttributedString as well as the mutable NSMutableString and NSTextStorage to cover different sizes and usage patterns for text.

Conclusion

As a word, "immutable" may sound like it is removing potential functionality from a class. In reality, using it where appropriate can make your interfaces between classes cleaner and easier to control. It also allows you to create code which closely reflects the aspects of values.

I have spent most of this post talking about immutable "value" classes. This is because classes which model entities that can be described as "values" are the canonical case for immutable classes.

Values are a good match for "immutable" design because an operator which acts on a value usually creates a completely new value. Values are also typically small objects (a few bytes to a few kilobytes).

Magic Number Machine's BigFloat class is still mutable since I never took the time to rewrite it. It didn't prevent the program working, it just required lots of careful copying and careful passing between classes. It also made the code for invoking operators less aesthetically pleasing.

Read more...

Supersequent implementation

Ever wanted to override a method using a category but still invoke the default method from the category? Like invoking the super method on a super class, this example will show you how to invoke any "supersequent" method no matter if its on the super class, the current class or even another category on the current class.

Method swizzling

In my opinion, the most fun feature of Objective-C's dynamic method lookup is being able to replace methods at runtime. For example, if you wanted to know when the -[NSWindow dealloc] method gets called and you're not using a subclass of NSWindow, you can exchange the normal -[NSWindow dealloc] method with one of your own methods and set a breakpoint or perform any logging work in your own code, before calling the original implementation.

This is done through an approach called method swizzling. An example of Method swizzling to replace -[NSWindow dealloc] method would work like this:

  • Create a class, MyClass, with a class method, +(void)myReplacementMethod
  • Put the following code at the start of your main() function:
Method myReplacementMethod =
    class_getClassMethod([MyClass class], @selector(myReplacementMethod));
Method windowDealloc =
    class_getInstanceMethod([NSWindow class], @selector(dealloc));
method_exchangeImplementations(myReplacementMethod, windowDealloc);

Prior to Objective-C 2.0 (in Mac OS X 10.5 Leopard) this code was a lot uglier. Google "method swizzling" and you'll see how people used to do it. Jonathan Rentzsch even wrote a library to handle all the different variations.

The contents of myReplacementMethod will now be called instead of NSWindow's dealloc. Conversely, if you wanted to invoke the original NSWindow method instead, all you need to do is invoke [MyClass myReplacementMethod]. This allows you to invoke the original implementation from your replacement implementation if you want to do so.

Limitations to method swizzling

The biggest limitation to method swizzling is that it only works if the method is implemented at the level you are trying to replace.

In the above example, this means that NSWindow must implement dealloc for us to replace it. If it merely uses an inherited version of dealloc then we must replace it at the NSResponder or NSObject level, affecting all NSResponder or NSObject objects, even if we only wanted to replace it for the NSWindow objects.

In addition, documentation rarely reveals whether classes implement overrides of inherited methods. So if you're trying to swizzle a specific method at a specific level in a hierarchy, you don't really know if it will be there until the swizzling fails or succeeds. And since overrides are typically "unpublished", you don't have any guarantee that it will remain there in the future.

It would be nice to have an approach which could replace at the NSWindow level, whether or not the method is implemented at that level.

A better proposal

I would like to be able to create a Category on a Class that overrides the method to replace but still lets me invoke the original method, like a "super" invocation but where it doesn't matter if the "super" method is on the current class or a super-class.

In the -[NSWindow dealloc] example, I just want to create -[NSWindow(MyOverrideCategory) dealloc] and still be able to invoke -[NSWindow dealloc] from my override.

Objective-C lets you create overrides in Categories but it prevents you from invoking the original implementation. This limitation occurs because Objective-C's "super" invocations only ever start from the super-class but Categories override methods on the same class.

This means, is that if you invoke [super dealloc] inside -[NSWindow(MyOverrideCategory) dealloc] it will invoke -[NSResponder dealloc] not the default NSWindow version.

I want to be able to invoke the "method immediately before the current method in the method lookup, no matter if its on the current or a super class".

Supersequent implementation

I didn't invent the word "supersequent" but I've never seen it applied to method lookup before. It seems about right in this case because we're looking up the next implementation in the "super" direction but it may not necessarily be a "super" method.

An invocation of the supersquent method implementation follows. This example shows a Category of NSWindow overriding dealloc and then invoking the default version.

@implementation NSWindow (MyOverrideCategory)

- (void)dealloc
{
    invokeSupersequent();
}

@end

Obviously, the magic is contained in invokeSupersequent(). This is a C preprocessor macro whose implementation is shown below.

No parameters to invokeSupersequent are needed here but the macro takes a variable argument list. The full set of method parameters (dealloc has no parameters) must be passed into invokeSupersequent() to be received by the supersequent implementation. The compiler will not warn you if you get this parameter list wrong, so you must be careful with it.

You can also use "return invokeSupersequent();" if you want to return the result of the supersequent invocation.

The lookup itself is relatively safe in that it will invoke any "super" implementation instead, if an appropriate next implementation is not found on the current class. The current implementation (shown below) is a little rough in that it tries to invoke nil when no "super" implementation exists at all but you could easily test for a nil result if you were concerned about that possibility.

The solution

The process works like this:

  1. Find the IMP of the current method.
  2. Look through the current Class's hierarchy and find the next method in the list after the current method (identified using the IMP from step 1) that responds to the same selector.
  3. Invoke that method

Step one comes from my earlier post of the same name.

Step two is just a series of iterations over the current Class' methods. It looks like this:

@implementation NSObject (SupersequentImplementation)

// Lookup the next implementation of the given selector after the
// default one. Returns nil if no alternate implementation is found.
- (IMP)getImplementationOf:(SEL)lookup after:(IMP)skip
{
    BOOL found = NO;
    
    Class currentClass = object_getClass(self);
    while (currentClass)
    {
        // Get the list of methods for this class
        unsigned int methodCount;
        Method *methodList = class_copyMethodList(currentClass, &methodCount);
        
        // Iterate over all methods
        unsigned int i;
        for (i = 0; i < methodCount; i++)
        {
            // Look for the selector
            if (method_getName(methodList[i]) != lookup)
            {
                continue;
            }
            
            IMP implementation = method_getImplementation(methodList[i]);
            
            // Check if this is the "skip" implementation
            if (implementation == skip)
            {
                found = YES;
            }
            else if (found)
            {
                // Return the match.
                free(methodList);
                return implementation;
            }
        }
    
        // No match found. Traverse up through super class' methods.
        free(methodList);

        currentClass = class_getSuperclass(currentClass);
    }
    return nil;
}

@end

And finally, step 3 is encapsulated in a macro which handily invokes the other two steps for you.

#define invokeSupersequent(...) \
    ([self getInstanceImplementationOf:_cmd \
        after:impOfCallingInstanceMethod(self, _cmd)]) \
            (self, _cmd, ##__VA_ARGS__)

Conclusion

Yes, you can invoke the default class implementation from a category on that class. In most cases though, since it is slower at runtime than method swizzling, it is primarily only useful for debugging where 5 lines less code makes it much easier to use.

The speed at runtime is slower than method swizzling because it bypasses cached method lookup. Where cached method lookup takes about 5 nanoseconds on newer machines, this approach takes about 5 microseconds on typical objects with around 50 methods in their hierarchy (slightly slower than uncached method lookup) and like uncached method lookup, it can take longer for classes with very large method tables.

There are a few other limitations as well. This approach will not work on message forwarding classes (like NSProxy) or where other fallbacks are used to handle messages when no method is found. Also, the compiler won't warn you if no supersequent implementation exists or you've passed the wrong number or type of parameters into invokeSupersequent().

Despite these three drawbacks, I still use this approach when I'm debugging. It is just one line to invoke and makes it very easy to replace a method on someone else's class.

Read more...