Best way to override the App Delegate?

In using ShareKit, I needed to modify the handleOpenURL: method (and similar methods) in ofxiPhoneAppDelegate. Is there a clean way to do this?

I think I’ve found a good way: Categories!

I create a new .h and .mm pair called ofxiPhoneAppDelegate+Extra

Then I can override AppDelegate methods like so:

  
  
@implementation ofxiPhoneAppDelegate (extra)  
  
-(void) applicationDidFinishLaunching:(UIApplication *)application {      
	NSLog(@"Extra Thing in DidFinishLaunching");  
	(the rest of the existing methods go here)  
}  
@end  
  

Include ofxiPhoneAppDelegate+Extra.h in my testApp.mm file, and the method runs! No modification made to core, though if the overridden method changes at some point in the core, it will need to be re-copied into the category.

Given the structure in ofxiPhone I don’t think there is a cleaner way to do this, and it’s not great because you have to copy the existing code into the category. Normally you would just subclass the appdelegate and use your subclass instead of ofxiPhoneAppDelegate but then you have to change the ‘core’ to use your subclass. That makes it just about as clean as just adding the extra thing in the current appdelegate…

The only thing that comes to mind is method-swizzling, which is awesome obj-c runtime stuff. It allows you to use a category, override the method and still call it’s original implementation. It works by swapping the insides of the original method and your replacement. Then you can call your replacement from the replacement which looks like recursion but it actually calls the original code because you just swapped them. Nifty!

So in your category:

  • add -(void)customApplicationDidFinishLaunching:(UIApplication *)application
  • implement +(void)load , this method gets called in every category when the class is loaded. get references to the methods and swap their implementations:
  
  
+ (void)load {  
    Method original =    class_getInstanceMethod(self, @selector(applicationDidFinishLaunching:));  
    Method custom =    class_getInstanceMethod(self, @selector(customApplicationDidFinishLaunching:));  
    method_exchangeImplementations(original, custom);  
}  
  

  • in -(void)customApplicationDidFinishLaunching:, call yourself!
  
  
- (void)customApplicationDidFinishLaunching:(UIApplication *)application {  
    NSLog(@"extra thing");  
  
    // this looks like recursion, but because the insides of the methods are swapped, we are actually calling the original implementation of the method  
    [self customApplicationDidFinishLaunching:application];  
}  
  

This is actually pretty nice, you’re not editing the ‘core’ (it’s not really the core, just an addon) and you have all your code in a category. It’s not recommended to use method swizzling too often though, as it can be dangerous to swap all implementations for a certain class. In this case it won’t be a problem as you’re only using the appdelegate once, but you can imagine that doing swizzling with UIView or NSObject can cause some problems down the road.

Thanks for posting, this will really help for adding external stuff that expects full AppDelegate access. More docs:
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocCategories.html#//apple-ref/doc/uid/TP30001163-CH20-SW1

http://en.wikipedia.org/wiki/Objective-C#Categories

Ron