|
This blog post will compare the NIB file vs. the XAML file. There are a couple of really obvious differences between the two, but I was actually pretty struck by the similarities - similarities that I never expected, especially given how much older the NIB file is than the XAML file, in terms of being publicly available.
The NIB
NIB stands for NeXTStep Interface Builder (I hope I got the capitalization right on NS... ). As you go through your typical Cocoa life cycle of building your application, you will at some point go into Interface Builder and work on the GUI of your application. Interface Builder lets you drag and drop UI elements onto various surfaces, let's you manipulate the menu bar for your application (For those who've never used OS X, there is a single, always-there menu bar that simply changes content when the active application changes), and many other things. Among my favorite features are the ability to instantiate things and see icons for the instances directly within the IB and the ability to visually connect outlets and commands just by control-dragging. Once you get used to it, the whole thing feels very natural. The downside for me is that there is no non-designer equivalent of the NIB file. I have always been "that guy who writes HTML in notepad" and more recently the guy who "writes XAML without a designer", and I love me some command-line - so I felt curiously out of place when forced to use the designer and only the designer. However, that said, I have not yet found a situation where I felt the need to abandon the designer in favor of a "notepad"-like equivalent.
How it works: As you drag elements around within the Interface Builder, you are essentially building a picture of what you want the interface to be like at runtime. Under the hood, IB is creating instances of all the runtime objects needed in order to produce the interface that you are designing. All these instances form a runtime graph of objects that is then archived (for those of you who are familiar with .NET or Java, an Objective-C archive is roughly equivalent to a .NET or Java serialization) into a stream of bytes stored in the .NIB file. In other words, the runtime state of your entire user interface is stored in the .NIB file. When your application starts, the UI is restored (that's de-serialized, kiddies) from the NIB file and activated. You can hook into the events around the restoration of your NIB file (referred to as "awaking from NIB", I think the delegate method is actually called awakeFromNib:) to make sure you take care of things that need to be done when the NIB file is loaded at runtime.
The XAML
XAML stands for eXtensible Application Markup Language and has been around since, I think, 2002. That's right kiddies, 200-freaking-2. It was probably around even longer than that internally at Microsoft, but I can't vouch for that, since I've never been internal to anything at Microsoft. If you had the luxury of being at the PDC 2003, then you saw Avalon (what would become WPF) unveiled in all it's glory, including the XAML language. XAML is an instantiation language. What that really means is that you get to use XML syntax for declaratively indicating what object instances you want in your runtime graph, and what you want their property values (state) to be. Sound familiar? It should. XAML serves the exact same purpose as the NIB file, only with slightly different implementations. XAML gives me the raw, low-level stuff that I like (I can type the XML directly without using a designer). Here's an example of what a XAML file looks like (in case you've been living under a rock for the past 4 years):
<Window x:Class="MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="My Window!" Height="300" Width="300" Closing="MyWindow_Closing"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="75"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Grid.Column="1" x:Name="MyButton"
Click="MyButton_Click">Click!</Button>
...
</Grid>
</Window>
Microsoft's Expression designers can do some pretty amazing things with WPF. Here's the problem I have: when using those designers, I find that it takes me 3-5 times as long to get the designer to do something that I can do directly in the XAML file just typing it by hand. Is this a poor design issue with Microsoft's designers? Possibly. Note that I mentioned that there is no way to avoid using the designer for a NIB file, yet I feel pretty quick and productive using IB.
The XML that you're looking at in the XAML file is built at compile-time into one half of a partial class. Remember that huge, colossal pile of crap that used to clutter all your WinForms 1.0 C#code files back in the days before partial classes were implemented on the .NET Framework? That's the crap that gets thrown into the compiled XAML file (partial class). The complexity of all the code required to create the UI state is hidden from you by the magic of partial classes, but it's there for the looking if you really want to find it.
The bottom line: Both NIB files and XAML files are representations of UI state that represent a specific chain of instantiation, allocation, and state manipulation (property changes). The NIB file uses IB to create instances of those objects and then archive them into a stream of bytes stored in the NIB file that will be restored when the Cocoa application starts up. The XAML file is parsed and turned into a .g.cs file that is the second half of a partial class, which is then compiled and all of the code in that file is run at application start-up, reproducing the UI state that you built in your designer (or favorite XML editor).
Which one is better? I'm not going to comment on that. I don't think it's fair to say that one is better than the other - there are subtle differences in NIBs and XAML that prevent a true "apples to apples" (pun intended) comparison. For example, the dynamic nature of Objective-C makes certain UI features far more simple (or even possible at all) in IB than Visual Studio 2005. Given that disclaimer, I really like Interface Builder. When I set IB up in my bottom-right "space" (I love spaces on Leopard!) and Xcode in my top-right space, I have the documentation / developer library in the bottom-left space, and it feels incredibly smooth, powerful, and comfortable. There are times when IB feels counter-intuitive to me (backwards, actually) and I miss being able to drop into the code, manually rig up a binding and hit "F5" and go... but I suspect that the counter-intuitive nature of IB has more to do with the fact that I've been writing code in Visual Studio since I started writing ASP applications with VS 6.0a years (many...many years...) ago.
(disclaimer: personal opinion here) I have noticed that as I find out more and more about some of the power available within Xcode and Interface Builder - I notice that there are a lot of things that the OS X developers have had for a long time that we're only starting to be able to enjoy with WPF such as true separation of UI and controller code via serialized (or code-generated) UI state.
As an ex-.NET developer, and since 2002 a huge Cocoa fan, I'm really
enjoying your articles about both technologies. Both platforms are great (I
think that .NET is maybe the best ever product to have shipped from
Redmond) but when you think that NIBs and Objective-C and the ancestor of
Cocoa were around almost 20 years ago in the NeXT... well, I wonder what I
was doing all this time :)
You don't have to use Interface Builder to lay out controls. Just make an
NSRect with the coordinates you want and call setFrame: on the desired
view. Remember, all IB is doing is sending messages to the objects and then
archiving them in a certain state. By definition, IB has to call methods
that exist in the class itself. Same goes for bindings -- you can do it all
in code.
I have only just started learning Objective C (I've been programming as a
hobby for the past 6 years) and I really enjoy reading about the
differences you find in a way that doesn't mindlessly bash Windows. You
explain everything in a way that's easy to understand and comprehend.
Check out this Podcast for cocoa developers www.cocoacast.com
Scott, I know you can write code to mimic what IB does. I think what I was
trying to convey was that I have to use the designer to lay out design-time
changes..but you're right, writing the ObjC code is equivalent (roughly) to
switching to notepad to create XAML.
You can also create IBPalettes http://www.bignerdranch.com/palettes/
Interface Builder also has the option to store NIBs as somewhat human
readable XML files. I sometimes hand edit such files and then read them
back into IB.
Also look at what is coming in Interface Builder 3.0... lots of nice
changes in the works for a tool that generally hasn't seen much of a UI
change since NeXT days.
So we can do withouth Foundation Collections Palette in Interface Builder
3.0?
Based on what you have shown, I think GNUStep Renaissance does what XAML
does. It is supposed to work with OSX but I have not tried it.
Actually, both Renaissance and binary/XML NIBs differ significantly from
XAML if I understand this article correctly. In neither instance does a
NeXTStep/OpenStep/GNUStep/Cocoa .nib/.gorm/.gsmarkup file cause code to be
generated (retch) and compiled. This has several advantages, including
easier localization and the ability to customize without having access to
the application source code. You only need a text editor, Interface
Builder, or GORM (depending on the file type) and you can customize. (Just
being able to move buttons around and adjust the positions and sizes of
form elements to suite my own tastes is a big plus to me.)
Robert is correct. When Visual Studio 2005 cranks through your XAML at
compile-time, it creates a pile of code (XAML is an instantiation language,
meaning it declaratively indicates lines of constructor invocations and
property setters) in a .g.cs file, which is an intermediate step. Then that
thing is converted into a binary, compiled version of XAML called a BAML
file.
In other words, the BAML file is similar in intent to the NIB file, though
the underlying plumbing and implementation may vary a bit. In short, NIBs
are optimized for Cocoa, and BAML is optimized for WPF.
A nib is actually also the inside of a cocoa bean, although I believe that
the name of the .nib extension precedes the name of the Cocoa framework by
several years. Does anybody know whether Cocoa was named because of this,
or is it all just coincidence?
I believe Cocoa was so named as a sort of pun on the name 'Java', since
Java borrowed so heavily from the ideas present in ObjC/OpenStep. Cocoa
is, similar to Java, a hot refreshing drink.