Software that doesn’t work with Mac OS X Lion

Since upgrading to Mac OS X Lion I’ve found the following software on my System that no longer works.

Games & apps that require Rosetta (PowerPC compatibility)

  • Age of Empires 2 Gold
  • Baldur’s Gate 2
  • Diablo 2
  • DooM Legacy
  • Railroad Tycoon 3
  • Starcraft

Games and apps that crash on start

  • The Dig
  • Indiana Jones and the Last Crusade
  • Guitar Rig 4 64bit (patch expected soon)

Even more Cocoaheads Presentations

I’ve continued my journey with Final Cut Pro X and created more videos from talks done at the June Melbourne Cocoaheads meetup. These videos are now up on the Melbourne Cocoaheads Vimeo group (and embedded below).

David Kennedy & Scott Manley of Dangerous Pixels speak about building their iOS app development consultancy and their application Task Caddy.

You can find a wrap-up from the Dangerous Pixel guys, with links, slides and other resources over on their blog.

Luke Cunningham & Jesse Collis on “Epic Refactorings and Patterns to Make Your Code Awesome”.

What’s wrong with this macro?

What is wrong with this Objective-C (and C/C++) macro?


#define RETAIN_PROPERTY(propertyName, newValue) \
    do { \
        if (propertyName##_ != newValue) \
        { \
            [newValue retain]; \
            [propertyName##_ release]; \
            propertyName##_ = newValue; \
        } \
    } while(0)

Looks pretty benign right? Well it is when you call it like this:


id n = [NSNumber numberWithInt:10];
RETAIN_PROPERTY(propName, n);

But what happens when you do this:


RETAIN_PROPERTY(propName, [NSNumber numberWIthInt:10]);

Well macros are just that, macros. They generate code. They substitute the text of the macro parameters and emit the body into your source. Unlike methods or functions, they do not evaluate their parameters before passing the result to the macro. So the macro above when called the second way will produce the following code:


    do {
        if (propName_ != [NSNumber numberWIthInt:10])
        {
            [[NSNumber numberWIthInt:10] retain];
            [propName_ release];
            propName_ = [NSNumber numberWIthInt:10];
        }
    } while(0);

Not quite what we wanted right. We’re leaking an NSNumber instance and creating two which are auto-released and we’ll probably have a zombie object stored in propName_ after the auto-release pool is drained. A nice confusing bug for us to stumble upon.

So how do we fix this?

Like so:


#define RETAIN_PROPERTY(propertyName, newValue) \
    do { \
        __typeof__(newValue) __A = (newValue); \
        if (propertyName##_ != __A) \
        { \
            [__A retain]; \
            [propertyName##_ release]; \
            propertyName##_ = __A; \
        } \
    } while(0)

The line __typeof__(newValue) __A = (newValue); forces the passed parameter to be evaluated and a result stored in the temporary __A. We can then use the temporary variable multiple times within the macro body without fear.

Bug fixed and we can get back to being productive coders.

Cancellable asynchronous searching with UISearchDisplayController

Apple’s UISearchDisplayController is a handy wrapper around searching for UITableViewControllers. UISearchDisplayController will send its delegate the following message whenever a user types something into the search bar:

 - (BOOL)searchDisplayController:(UISearchDisplayController *)controller 
shouldReloadTableForSearchString:(NSString *)searchString

It is in this method that the delegate should perform a search of its data and based on whether the search results have or would change return the value YES or NO.

This all works fine and dandy when the objects to search are in memory and the delegate method executs promptly. If this is not the case then the UI will block while the search logic is performed. This can create significant lag in the user interface as the user is typing into the search field.

In the iOS API documentation for searchDisplayController:shouldReloadTableForSearchString: Apple provides a hint about performing search work in the background but doesn’t really go into any detail. The docs say:

You might implement this method if you want to perform an asynchronous search. You would initiate the search in this method, then return NO. You would reload the table when you have results.

An approach to doing an asynchronous search might be something like this:

@interface MyUISearchDisplayDelegate ()
@property (nonatomic, retain) NSOperationQueue *searchQueue;
@property (nonatomic, retain) NSArray *searchResults;
@end

@implementation MyUISearchDisplayDelegate
@synthesize searchQueue, searchResults;

- (id)init
{
    if ((self = [super init]))
    {
        self.searchResults = [NSMutableArray array];
        self.searchQueue = [[NSOperationQueue new] autorelease];
        [self.searchQueue setMaxConcurrentOperationCount:1];
    }
    
    return self;
}

- (void)dealloc
{
    self.searchResults = nil;
    self.searchQueue = nil;
    
    [super dealloc];
}

// ...

 - (BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
   if  ([searchString isEqualToString:@""] == NO)
    {
        [self.searchQueue addOperationWithBlock:^{
            
            NSArray *results = // fetch the results from 
                // somewhere (that can take a while to do)
            
            // Ensure you're assigning to a local variable here.
            // Do not assign to a member variable.  You will get
            // occasional thread race condition related crashes 
            // if you do.            

            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                // Modify your instance variables here on the main
                // UI thread.
                [self.searchResults removeAllObjects]; 
                [self.searchResults addObjectsFromArray:results];
                
                // Reload your search results table data.
                [controller.searchResultsTableView reloadData];
            }];
        }];
        
        return NO;
    }
    else
    {
        [self.searchResults removeAllObjects];
        return YES;
    }
}

This implementation gets you some of the way there. The problem with it however is that as the user interacts with the UISearchBar the searchString changes and with each character typed another invocation of searchDisplayController:shouldReloadTableForSearchString: is performed. This causes lots of work to be enqueued into the NSOperationQueue. Work that must get executed in sequence.

This is not ideal. The user is only interested in the most recent search string that they have entered. If they enter the string “fubar” into the UISearchBar they don’t care about the searches for f, fu, fub, and fuba.

OK. So how do you properly implement this? Well, it is surprisingly easy. Just cancel all the existing operations in the NSOperationQueue before adding your latest search operation to the queue.

     [self.searchQueue cancelAllOperations];

Any yet to execute operations will be cancelled and never execute. Any presently executing operation will run to completion. In a more complex situation, perhaps with a multistep NSOperation, (where you were using a custom subclass of NSOperation or something) you could check for isCanceled on NSOperaton instance and bail out of your operation early. I’ll leave that up to you to figure out.

So, with this change the code becomes:

 - (BOOL)searchDisplayController:(UISearchDisplayController *)controller 
shouldReloadTableForSearchString:(NSString *)searchString
{
   if  ([searchString isEqualToString:@""] == NO)
    {
        [self.searchQueue cancelAllOperations];
        [self.searchQueue addOperationWithBlock:^{
            
            NSArray *results = // fetch the results from
              // somewhere (that can take a while to do)
            
            // Ensure you're assigning to a local variable here.
            // Do not assign to a member variable.  You will get
            // occasional thread race condition related crashes 
            // if you do.            

            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                // Modify your instance variables here on the main
                // UI thread.
                [self.searchResults removeAllObjects]; 
                [self.searchResults addObjectsFromArray:results];
                
                // Reload your search results table data.
                [controller.searchResultsTableView reloadData];
            }];
        }];
        
        return NO;
    }
    else
    {
        [self.searchResults removeAllObjects];
        return YES;
    }
}

One final little thing, it is probably a good idea to cancel any pending operations when the user dismisses the search UI.

- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
    [self.searchQueue cancelAllOperations];
}

You may wish to cancel any pending operations in other delegate methods too. Such as tableView:didSelectRowAtIndexPath: for example.

Using p4merge as a custom Git merge tool on Mac OS X.

On Mac OS X Git uses the opendiff(1) command line utility as its merge tool by default.

opendiff(1) will launch the FileMerge app that comes with XCode when performing merges. Unfortunately FileMerge is not a very good merge tool.

To improve this, there are a number of options. There are some good commercial, Open Source and freeware diff tools out there for Mac OS X such as DiffMerge, SureMerge, Araxis Merge, K3Diff, and p4merge, etc. Too many to list them all here.

For my system I chose p4merge. p4merge is part of the Perforce source control management system. I’ve used Perforce quite a lot in the past at previous jobs and it has great tools. Perforce is commercial software, and I’m not about to use Perforce as my source control system instead of Git, but fortunately you can download and use the Perforce GUI tools for free. The Perforce merge tool is not tied in any way to the Perforce SCM system so you can use it as a stand alone tool.

To set up p4merge as my mergetool with Git I did the following:

  1. Downloaded the Perforce Visual Client disk image from Perforce.com
  2. Installed p4merge into /Applications.
  3. Added the these settings to my ~/.gitconfig file.

Now git mergetool will launch p4merge as my preferred merge tool.

p4merge Screenshot

Now you may be wondering why I didn’t just set my Git merge.tool config setting to p4merge, as it is supported “by default” by Git. Well, Git expects the command p4merge to be in the $PATH and I’d rather not have to install shell scripts across the different Mac systems I use so that it works “out of the box”. I also found p4merge wasn’t dealing well with the relative paths that Git was trying to pass to it, hence the custom mergetool.custom.cmd setting that uses $PWD.

Use the right cable.

Lately I had become somewhat dissatisfied with the speed of my QNAP 509 Pro NAS. In particular with the speed of transfers to and from it. I was thinking about getting another one, or replacing the drives in and effort to speed it up.

But then I gave it some thought and figured I should probably first do some more testing and research.

QNAP advertise the NAS I have as being able to get a sustained 60 megabytes per second in file transfers over a single gigabit ethernet link. This is pretty respectable. However, I was only getting at most 12MB/s. At first I thought that my iMac not supporting “jumbo frames” could be the problem. But with a little more digging I discovered the QNAP doesn’t support jumbo frames either so that wasn’t going to help me anyway.

In an effort to rule out the iMac as the problem I hooked up my MacBook Pro, which is normally only connected via Wi-Fi, to the Apple Time Capsule that is serving as my gigabit ethernet switch and did some more testing. The MacBook Pro was having similarly bad performance transferring to and from the QNAP. In an effort to discover if data transfer performance was just generally bad or if it was just the QNAP that was suffering bad performance I tried transferring files between my MacBook Pro and my iMac. This is where things started to get interesting. My MacBook was happily transferring data to and from my iMac at around 60MB/s.

It was at this point that a silly thought popped into my mind. Perhaps the cable connecting the Time Capsule to the QNAP just wasn’t up to snuff when it came to gigabit ethernet. So I changed it, and things got better. Fast.

Afterwards I realised that the cable I had been using all this time, to connect my QNAP to the rest of the world, the cable that I had just randomly selected from the large collection I have, was a cable I made myself a long time ago when CAT5 and 100MBps networks were the norm. The cable I replaced it with was a professionally made, modern, CAT5E cable. One designed to work with gigabit ethernet.

What a difference using the right cable can make.