Nat! bio photo


Senior Mull.

Twitter RSS


Decoding old Nibs. A sad tale of vendor lock-in and abandonment.

I have over 200 Nib Files of which most of them have EOInterface objects in them. The problem is, that they don't open in the newer Interface Builders.

Nibs are an Apple user interface serialization format. Why can't I edit them ? See Idea #3

With "new" i mean any Interface Builder with a version number higher than 2, especially those, that are integrated into Xcode. If I redo 200 NIBs manually, I am spending a year on this alone.

Idea #1: Use MEUnarchiver to dearchive

Use MEUnarchiver to decode the NIB archives. Create a fake runtime to dynamically create classes, that decode and detect the archive until everything decodes and the initWithCoder: method has basically written itself.

That was technological too interesting not to try, until I realized a few hours later, that I don't have a problem decoding in the first place... The nibs still load fine, but I can't edit them.


Idea #2: Write out ObJC code during NSKeyedArchiver

Load the NIB "manually" and substitute various strategic classes with invocation sinks a la

- (void) forwardInvocation:(NSInvocation *)invocation
   NSLog( @"added -[%@ %@]", _name, NSStringFromSelector( [invocation selector]));
   [_invocations addObject:invocation];

- (NSMethodSignature *) methodSignatureForSelector:(SEL)selector
   return( [NSMethodSignature signatureWithObjCTypes:"v@:@"]);

then use a custom subclass of NSKeyedArchiver that in parallel to the regular operation also archives into ObjC code. That sounded promising.

Unfortunately, the objects that are dearchived are not necessarily the same as those that you would want to archive. In other word dearchiving is sort of a lossy operation.

The basic idea could still work, but it's a lot of work and piggybacking on top of NSKeyedArchiver is probably not a good idea.

Idea #3: ibtool with custom IBPlugin

I created some IBPlugins that contained the required Frameworks. I thought that ibtool could magically transform the NIB to XIB without complaining and I could deal with the other problems somehow later. IBPlugin is a technology, that was abandoned by Apple with the advent of Xcode 4.

But it doesn't work, as ibtool is eager to note:

EOAspectConnector connections are not supported by Interface Builder 3.0.

More wasted time for another dead end.

Idea #4: nib2objc

Use and modify nib2objc. As amusing as it is tragic this projects GUI uses Apple's equally abandoned Garbage Collection technology. So it doesn't work anymore. There are some maintained forks, which also mostly still use GC ...

Anyway all these variants use ibtool to convert the input into a plist or XML representation first, so this is a non-starter.

I would have to mix up Idea #1 with #4 to get something going here, and nib2objc is for UIKit apps anyway.

Idea #5: Use GORM to edit the files

I didn't find any recent success story of someone getting Gnustep to run on OS X. So I assume GORM doesn't run on OS X but just on Linux, that's already pretty inconvenient for me. I don't know how compatible the palettes are. It sounds like a lot of work. Also GORM looks extremely ancient.

Idea #6: Convert NIBs to post 10.2 "human readable" XML

I am not sure what that's gonna buy me. The XML is readable but highly unscrutable. This is in no way better than Idea #1.

Idea #7: Use IBInspectable

This doesn't really work well for the kind of custom bindings EOInterface needs. It's good, that you can put NSObject based instances into XIBs (again ?), but the kind of typed connection EOInterface has are not possible with IBOutlet alone (unless you expose every EOAssociation). But I can't load the NIBs anyway, because the loader complains even with all classes present.

What I really want

What I really want is a simple file format, where I can structure the UI without any geometry or style information. Just type it in like the following example, and a custom unarchiver creates an ugly but working UI from it:

NSWindow                        window
            NSTableColumn           name
            NSTableColumn           age     
                EOTableColumnAssociation    assoc0
            NSTableColumn           sex
            NSTableColumn           birthday
                NSDateFormatter birthdayFormatter
    NSView                          whatever

NSWindow                        window2
        NSTextField             name2

EODisplayGroup                  group

This would build the hierarchy and gives out classes and IDs to objects. The first string is the class, the second string is the ID. The hierarchy is formed by identation.

I want to make connections with outlets, actions and EOAssociations somewhat similar to this, possibly in the same file. The property are accessed with standard KVC. This would be a separate section, or maybe just a separate file for now.

// create an action and connect an outlet
    action = FirstResponder.doSomething;

    outlet = birthday;

    value    = group.age;
    enabled = group.isEditable;

I want to style everything with some sort of CSS or probably more than likely just with CSS and key value coding itself. Also in a separate file for now:

   frame:               25px 50px 75px 100px;
   backgroundColor:     #ffeecc;

    formatString:           L"hhmmdd HHMM"M;

This is could be a little bit too string based, but that's solvable, with some linting.

This is actually just as easily said as it is done (2 days of work). I created MulleIB, which can do the deserialization in very simple cases. Now I need to get the serialization happening, but that shouldn't be too bad either, if I forego using NSCoder and just do it myself also.


A photo of Marcel Weiher

From: Marcel Weiher

Yes, it turns out that object-serialization is an idea that seems very good at first...

Also: what you describe sounds a lot like an Architecture Description Language, which has always been part of what IB was (avisual ADL).

A photo of Phil Barrett

From: Phil Barrett

I went through this sort of pain maybe 15 years ago converting a load of NeXTSTEP nibs first to OPENSTEP then to OS X, through a series of increasingly newer Interface Builders, each able to load nibs slightly but not a lot older than themselves. Very glad I don't have to do that again.

A photo of Nat!

From: Nat!

In a way HTML is also object serialization. I don't see a clearly defined border. Inscrutable object serialization is a drag though.

But all these XML like markup languages are a pain to use w/o tools.

I think the separation of design and structure is actually more benefical in desktop/mobile apps then in web. Now I could have a CSS for Linux and one for Windows and keep the rest pretty much intact.

The choice of CSS gets me hopefully some leverage unto SASS. In the end, that's how I want to do interfaces on Linux in the future, when the OS X ship has sunk.

A photo of Tim

From: Tim

I once wrote something very similar to your "What I really want", but in Scheme, and for a different (and mostly dead now) GUI toolkit.

It works really well, and is a dream to maintain -- right up until you hit that one weird case, and then another, and then another.

You end up with a choice. On the one hand, you can add a bunch of extra logic to handle these cases in your description file, and get something pretty much as complex as IB.

Or you can keep the file simple and do all the non-trivial things in code after it's loaded, which ends up meaning that half of your GUI description files are empty placeholders for things built in code, and the simple description file loader doesn't really buy you much over just writing native lists in your programming language, and a 5-line function to instantiate them by name/type and add them to their parent container.

A photo of Nat!

From: Nat!

Yeah, I can see, how I will end up having to rewrite NSCoding for all the NSView classes, but they aren't that many. If I do the editing only in the files and have just a "viewer" otherwise, the workload should be manageable.

I hope :)

Post a comment

All comments are held for moderation; basic HTML formatting accepted.

E-mail: (not published)