Making NSApplicationDelegate and NSDocument Play Together in OSX 10.8

I found it difficult to setup a NSApplicationDelegate for a Document-based Mac 10.8 (Mountain Lion) application (NSDocument) using ARC.

There's a lot of handy app specific methods in the delegate protocol that you'll most likely want in a new Mac app.  However, the project template (Xcode 4.4) does not include the ApplicationDelegate class. This missing puzzle piece meant I had to figure out how to configure it correctly with Xcode's Interface Builder.

Problem with NSApplicationDelegate

I tried adding an Object as my ApplicationDelegate in my PSDocument.xib file. However, that led to random crashing (EXC_BAD_ACCESS objc_msgSend_vtable5) when I closed windows from my app.

1. The reason it crashed is that the document window was deallocated, and the PSApplicationDelegate object was attached to it. This caused the NSApplication to invoke methods on a previously deallocated object. (i.e. PSApplicationDelegate)

2. Zombies to the rescue. See the screenshot on how to enable zombies if you're new to Xcode. Using zombies I was able to figure out a general idea of what happened.

Zombie Objects

Solution

Add the PSApplicationDelegate object to your MainMenu.xib file. It'll persist until you exit your app, rather than your document windows.

1. Drag the Object (blue-box) from the Object Library to your side panel in Xcode's Interface Builder.

2. Create the NSObject class called PSApplicationDelegate.h/m

3. Conform to the NSApplicationDelegate protocol

#import <Cocoa/Cocoa.h>
 
@interface PSApplicationDelegate : NSObject<NSApplicationDelegate>
 
@end

4. Rename the Object (blue-box) to PSApplicationDelegate

Custom Object in Xcode 4 4 Interface Builder

5. Control-click or right-click and drag from the File's Owner (NSApplication) to the new PSApplicationDelegate object (blue-box)

6. Select delegate.

NSApplicationDelegate Example for Document-based Mac OSX apps

 

Now you're golden and use any of the protocol methods from NSApplicationDelegate.

#import "PSApplicationDelegate.h"
 
@implementation PSApplicationDelegate
 
// Delegate methods
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
    NSLog(@"Started app");
}
 
 
@end