Custom Classes in Nibs

We looked at how Nib files contain arbitrary object instances, and how Interface Builder lets you create them by just dragging one off of a palette. Cocoa lets you do a decent amount with the default controls, but what about getting your own code in there?

Well, you can change the class of an object in Interface Builder. What this does depends on the object in question. For File’s Owner, it doesn’t affect the object passed in at all — because at design-time File’s Owner is just a placeholder, and at run-time it’s already been created before the Nib even starts loading. Changing the class just informs IB so that at design-time, it can represent that class more accurately.

You can’t change First Responder’s class at all, for obvious (if you read the article on Actions) reasons.

For objects actually serialised in the Nib, you can change which class will be instantiated at run-time. IB won’t run code from your custom classes at design-time (unless you’ve built an IB plugin, but let’s not go there right now) but it’ll be there when the Nib’s loaded. This is how you typically set up custom classes in IB — create a (non-custom) instance first, by dragging it off the palette, then change its class to one of your own.

Note that IB constrains the classes you can change an object to, to subclasses of the original. You should probably drag out the closest ancestor of your custom class — which might be something common like NSButton, but could be NSView is very custom, or even NSObject if your class is not a user-interface widget. When you switch to the IB inspector’s “identity” page, the “class” drop-down list is pre-filtered to the relevant branch of the class hierarchy.

Something to bear in mind, is that many of the widgets in Interface Builder are constructed out of several objects glommed together. A Table View, for instance, actually comprises an NSScrollView, NSScrollers, NSClipView, NSTableView, and one or more NSTableColumns, which in turn host various NSCells (of which more on another occasion). Dragging a Table View off the palette and onto your application’s window instantiates all of these, and IB still lets you drill down to the individual components and customise them. You don’t need to, say, subclass NSTableView, or write setup code, just to make a table use a YourSpecialisedTableColumn class.

But how does IB even know your custom classes exist? How does it know where they belong in the class hierarchy, or their other information? In version 3.0, XCode/Interface Builder will find your classes automagically, if the source code is added to the XCode project. It inspects them to keep the design tools up-to-date, with the right Actions and Outlets (in earlier versions, you had to enter this data by hand). Impressively, IB 3.0 inspects classes in any language that supports the new Cocoa Script Bridge technology, so you can write:


example using PyObjC
class SomeClass(NSObject): progressBar = IBOutlet() # pretend we just added this line to an existing class

…save the file, click over to Interface Builder, and any SomeClass instances now have progressBar members which you can drag connecting cables out from, to hook them up to widgets. You don’t even need to be editing the Python source in XCode; I always use TextMate for this and it picks up on the changes just fine.