Working without a nib, Part 6: Working without a xib

I bear a heavy burden now, for with the ongoing Hollywood writers strike I am the lone remaining source of pablum in the world. Actually, I was on strike too, from the bagel shop. You know I can’t blog without bagels! However, the recent reconciliation of DLR and EVH inspired us to put aside our differences, and I thought the offer of SCO stock options and tickets to a Broadway show was more than fair. Thus, there will be a series finale to Working without a nib. Maybe they’ll even name a space shuttle after my cat.

Speaking of cats — as I am prone to do — there is a new cat on the Mac (though none on the mat). Apple finally released Mac OS X 10.5, code named “Leopard”, followed soon thereafter by Mac OS X 10.5.1, code named “Oops”. These updates to Mac OS X pose a problem for the Nibless project, because the crucial method +[NSObject poseAsClass:] has been deprecated in Leopard. In fact, this method does not work at all in the Leopard 64-bit runtime.

Fortunately, the new Leopard Objective-C runtime provides a nice solution to the problem. In earlier versions of Nibless we used poseAsClass: to override +[NSBundle loadNibNamed:owner:] while still allowing the original method to be called. We can accomplish the same thing in Leopard via a technique that computer scientists have termed the old switcheroo:

Class bundleClass = [NSBundle class];
Method originalMethod = class_getClassMethod(bundleClass, @selector(loadNibNamed:owner:));
Method categoryMethod = class_getClassMethod(bundleClass, @selector(JJ_loadNibNamed:owner:));
method_exchangeImplementations(originalMethod, categoryMethod);

These functions are documented in the Objective-C 2.0 Runtime Reference. It is straightforward to exchange the method implementations; the mind-bending trick is to call the original implementation afterward.

+(BOOL) JJ_loadNibNamed:(NSString *)aNibName owner:(id)owner
	BOOL didLoadNib = YES;
	if (aNibName != nil || owner != NSApp)
		didLoadNib = [self JJ_loadNibNamed:aNibName owner:owner];
	return didLoadNib;

Before the function method_exchangeImplementations() is called, the method JJ_loadNibNamed:owner: has the implementation defined above, but the method never gets called until that implementation has been given to the method loadNibNamed:owner:, at which point the method JJ_loadNibNamed:owner: has the original implementation of loadNibNamed:owner:, whatever that may be (only Apple and Uri Geller know for sure). We never get caught in an infinite loop, unlike poor Alice and Norman.

The Leopard version of Nibless you’ve long been waiting for — since the second paragraph — is ready for download. If you find it useful, then please send me a bagel. I’ll also accept a doughnut, but not a Danish. Spoon!

Comments are closed.