I’ve decided to learn Cocoa and Objective-C by creating a simple application for tracking shipments. The idea is that users will be able to enter shipments and their expected arrival date, and get a little alert from the application if the arrival date has passed and the shipment has not arrived. Simple stuff, I hope. I’ll call it IntelliTrack. This will all be done in Xcode, because I cry when I don’t have Apple’s instructions on how to do things.
I began by creating a very basic application in Xcode. If you don’t know how to do that, working through this tutorial is very good to getting you started, and it’ll make following the rest of this easier. I basically don’t go over anything written there, since that tutorial is very self-contained.
With IntelliTrack set up in Xcode, I decided try to create a main window with a toolbar (easy) that has a search field (trouble).
I opened IntelliTrack/Resources/MainWindow.nib, which opened the UI of the application in Interface Builder. I selected an NSToolbar as the object to add from the library and dragged it onto the window title bar. This made the application window look like this:

A window with the default Cocoa Toolbar
Nice for a few drag-and-drop actions, but there’s no search field there. Worse, there’s stuff I don’t need, like, well everything there. I wanted a toolbar that displays only the things I want it to display, and nothing more.
To find out how NSToolbars work, I went here, and found out that toolbars have a certain default behavior that can be overridden by their delegate. Basically, a toolbar has a delegate that must implement three methods:
- toolbarAllowedItemIdentifiers returns the identifiers for the allowed items
- toolbarDefaultItemIdentifiers returns the identifiers for the items that appear in the toolbar by default if they are not overruled by the user preferences .
- toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar: returns the requested item.
(Note that there are other delegate methods that can optionally be implemented, as described in the NSToolbar documentation.)
Given that, I wanted a delegate that would:
- allow all the items that the default toolbar allows, as well as a custom search field
- by default show only the search field, flush right.
So, first things first, I created the delegate class. In Objective-C, that means I had to create a header file and an implementation file, the header file serving as the class’ interface to the world. The code for the header file can be found here, with comments to explain how things work. The corresponding implementation is here. These files reside in the IntelliTrack/Classes folder.
Fun facts:
- Java and Ruby developers might notice that ITToolbarItemDelegate inherits from NSObject. NSObject is the equivalent in Cocoa of java.lang.Object or of Ruby’s root Object class. Inheritance must be explicitly stated because the compiler is not actually aware of the runtime. This bears repeating: the Objective-C language is separate from the Cocoa runtime provided by Apple. Objective-C simply provides a working syntax for calling objects (i.e., it will call the object you specify if it exists); it does not provide a root object to build from, or a set of libraries. In the (vaguely terrifying) words of the Cocoa documentation, if you wanted to, you could write your own root object…
- Java and Ruby developers might also notice that most variables are prefixed with an asterisk when they are declared. This means that the variables are pointers to a value, rather than the value itself. It essentially works the same way as a regular declaration in Java or Ruby. Variables that do not get the asterisk are the actual values themselves. This is unheard of in Java and Ruby-land, but don’t ask me to go into too much detail here, as I’m just learning this myself.
- [NSArray arrayWithObjects:firstElement...] must have nil as its final parameter. No idea why; if someone could explain it, that would be great. I do know that if that convention is not followed, running the application gives a nasty EXC_BAD_ACCESS error.
At any rate, I had to remember to turn on garbage collection, and upon building, I was ready to finish the set up of the toolbar.
Three things remained to be done: create a search view, connect the toolbar to the toolbar delegate, and connect the toolbar delegate to the search view.
First, creating the search view is easy: I just dragged the NSSearchView from the library onto the MainMenu.nib window, and it appeared. For the toolbar delegate tasks, I imported the toolbar delegate by dragging an Object item from the library onto the window, and selecting ITToolbarDelegate as the class in the identity tab of its inspector. I then connected the searchToolbarItemView outlet (defined in ITTolbarDelegate.h) to the search view. Finally, I connected the toolbar’s delegate outlet to the toolbar delegate object in the window. At the end, the window looks like this (unfortunately, the connections are not visible):

The MainMenu.nib file
At last! It was ready to go. I compiled and ran (and debugged, and ran…) the application, expecting a nice toolbar with nothing but a search field. Instead, I got this:

The actual result of all my efforts. Note depressing plethora of items.
This despite the fact that the delegate method clearly returned only the flexible space and search items. The problem was that I hadn’t deleted the original items that appeared by default in the design view. As such, the toolbar thinks all those items are available (which is true) and to be displayed (which is not). It seems that the toolbar at this point either merges or concatenates the items that are displayed in the designer window with those that are returned from the delegate method, and shows the resulting set. After deleting the original items (this is done by double-clicking on the toolbar in the design view, and deleting all the items from the sheet that appears) and recompiling, I finally got the toolbar I was looking for:

Triumph at last!
Unfortunately, some bugs remained, but I’ll go over those in a future post. Please feel free to leave any comments and corrections.