A few pointless posts ago, I was talking about Nibless Cocoa applications, and how Jeff Johnson, had a ready to use solution for us, Interface Builder cheaters. Jeff's elegant solution is build around using Cocoa
So ... since I'm interested in a solution that can work from 10.4 and beyond on PowerPC and Intel, 32-bit as well as 64-bit, I had to go back to the drawing board and come-up with an alternative solution, likely something not as elegant. Hopefully, thanks to Objective-C's dynamic abilities, it is possible to replace on-the-fly a method implementation by another function (as long as it have a compatible signature). Scott Stevenson have made a an excellent post on this, which I used as the base of my solution.
The idea is relatively simple: replace the
NSObject
's ability to have a class pose as another class (but it must be a parent class). The trick been to make sure that when the application is starting, the NSBundle
created to load the main NIB file does not load it, and instead just pretend to have done so. The method works like a charm (granted that the entry NSMainNibFile
in info.plist has been removed), however there is just a little problem: the class method poseAsClass
has been deprecated in OS X 10.5 and is not even present in 64-bit Cocoa. I have no idea whatsoever this is been phased-out by Apple. Since a similar facility exists in Objective-C and GNUStep, it's not clear at all why this have to go ... Security concern maybe? Whatever the explanation, I'd like to know ...So ... since I'm interested in a solution that can work from 10.4 and beyond on PowerPC and Intel, 32-bit as well as 64-bit, I had to go back to the drawing board and come-up with an alternative solution, likely something not as elegant. Hopefully, thanks to Objective-C's dynamic abilities, it is possible to replace on-the-fly a method implementation by another function (as long as it have a compatible signature). Scott Stevenson have made a an excellent post on this, which I used as the base of my solution.
The idea is relatively simple: replace the
NSBundle
's class method loadNibNamed:owner:
by my own implementation function and call the original method only in when necessary. Since I wanted to have this automatically done as part of a special type of application, I derived NSApplication
in HZNiblessApplication
, implementing its object method init
to do the dirty work:- (id) init { if ((self = [super init])) { Method lMethod = class_getClassMethod([NSBundle class],@selector(loadNibNamed:owner:)); if(!lMethod) NSLog(@"NSBundle+loadNibNamed:owner: not found!"); else {#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 gDefaultNSBundleLoadNibNamed = method_setImplementation(lMethod,(IMP)loadNibNamed); #else gDefaultNSBundleLoadNibNamed = lMethod->method_imp; lMethod->method_imp = (IMP)loadNibNamed;#endif } } return self;}
As your can see, the method basically retrieve the method within the
NSBundle
class, and swap its implementation with a function called loadNibNamed
. Since we need to call the original method to perform its duty when there is a need to load a bundle, we save the pointer to the function in a global variable named gDefaultNSBundleLoadNibNamed
. Let's have a look now on how that replacement function is implemented:BOOL loadNibNamed(id aObject,SEL aSelector,NSString *aNibNamed,id aOwner){ if (!aNibNamed && aOwner == NSApp) return true; else return (BOOL)(*gDefaultNSBundleLoadNibNamed)(aObject,aSelector,aNibNamed,aOwner);}
From there, all that is needed is to replace the value of the
As you have noticed, I finally figured a way of putting neatly formatted code (hmm ... at least on Firefox) on this blog, courtesy of github.com.
NSPrincipalClass
key in the application's info.plist
by HZNiblessApplication
and get your application delegate to fill in the Application menu from -applicationWillFinishLaunching:
... Okay, yeah I'm simplifying a bit here, but you get the point I'm sure :-PAs you have noticed, I finally figured a way of putting neatly formatted code (hmm ... at least on Firefox) on this blog, courtesy of github.com.
No comments:
Post a Comment