This article is more than 1 year old
Uncle Mac takes A Cup of Cold Cocoa...
A first diatribe from the Grumpy Old Man
'Twas the night after Christmas. The left-over turkey had been stuffed into the freezer, the surplus mince pies stuffed into the dog, and my thoughts turned once more to programming – Mac programming. Seduced, as ever, by the Aqua interface, I decided it was time to write that killer Mac utility, the proceeds from which would magically transport me to balmier climes, somewhere where the air was redolent with spices rather than day-old sage & onion stuffing…
I fired up XCode, created a new Cocoa application and launched Interface Builder (IB) to begin my user interface design. Dropping a NSTableView
control onto the new window, I looked around eagerly for IB’s equivalent of the Delphi Property Inspector so that I could set the table to automatically perform a column-based sort, just like the Apple Finder does. While I was at it, I also wanted to set some kind of AcceptDroppedFiles
property so that users could drop files directly onto the table.
Note: No, I’m not going to tell you what my killer Mac utility does, or you just might get there first. As far as balmier climes are concerned, my need is greater than yours, ok?
Well, guess what? Interface Builder doesn’t have a Property Inspector. An Inspector window, yes, but not a property Inspector window. This is very possibly because Cocoa objects don’t actually have properties. In fairness, the upcoming new release of Objective-C 2.0 (in Leopard) will have property support. (See the info here, which has been gleaned from an inspection of Apple’s branch of the GCC sources).
Of course, we Delphi and C# developers understand that a property is usually just syntactic sugar-coating around a method call, right? So presumably, there are methods (errr...sorry…messages) which will give me auto-sort tables and file drop facilities, right?
Nope. If you want such user-interface baubles, you must do the job yourself. In the case of auto-sort tables, you have to respond to a snappily-named tableView:didClickTableColumn:
message (and compared to a lot of Cocoa messages, that’s pretty damn snappy!) which, if all this stuff were written in Delphi, would probably be an OnColumnClicked
event. You then need to display a little sort glyph (up or down pointing arrow) in the appropriate column header, and reverse the sort order if the user just clicked the column header that’s already sorted - IYSWIM.
Naturally, Apple doesn’t provide the images for you to do this. Well, it does, but they’re undocumented. You can adopt the really dirty approach using the internal, undocumented _defaultTableHeaderReverseSortImage
and _defaultTableHeaderSortImage
messages to get the images; or you can be a purist and create your own custom glyphs from scratch. I didn’t want to get dirty, and I don’t have the artistic skills to “do it proper”, so I cheated and used “NSAscendingSortIndicator” and “NSDescendingSortIndicator” as parameters to the NSImage imageNamed:
message. That particular wheeze is documented, but… not by Apple. I won’t bore you with the details of the sort itself. Suffice to say that the NSTableView
won’t do it for you.
And then there’s file dropping. Once you’ve registered your table to receive filename drops, you then need to give the thumbs-up once a file drop operation is under way. This is done using the code below. Now you see why I referred to tableView:didClickTableColumn:
as being snappily-named!
// Called to validate a file drag-over operation - (NSDragOperation) tableView: (NSTableView *) tv validateDrop: (id <NSDraggingInfo>)info proposedRow: (int) row proposedDropOperation: (NSTableViewDropOperation) operation { [self setDropRow: -1 dropOperation: NSTableViewDropOn]; return NSDragOperationCopy; }
When it comes to hooking up the user interface to your actual Objective-C code, you’re suddenly thrown into the bizarre world of outlets and actions. Maybe I’m dim, but I had to read three Cocoa programming books before I finally found a reasonably cogent explanation of this. Again, in Delphi or C# terms, an “action” is simply an event handler; a method that gets triggered (if you prefer, a message that gets sent) when some user interface event takes place. An outlet, on the other hand, is an object instance variable which connects the code back to the user interface – it allows your Objective-C code to reference a particular pushbutton, checkbox, or whatever. Fundamentally, actions map from interface to code, while outlets map from code to interface.
The reason for this strange dichotomy between interface and code is pretty obvious; XCode, the Objective-C IDE, understands code rather than visual interface layout; while Interface Builder, as the name suggests, understands interfaces and not code. To put it bluntly, XCode desperately (and I do mean desperately!) needs an integrated form designer. Imagine being able to drop a pushbutton control onto a form, double-click it and – bang! – there you are in the code editor, with an insertion caret inside your event handler. Imagine not having to “introduce” your code to each element of your user interface design. Alas, such joys are entirely unknown to Cocoa programmers; as perhaps, are the joys of terse method names.
OK, I’m being a little tongue in cheek here, but I really think that if the average Cocoa programmer spent some time with Delphi, s/he’d be totally blown away. Naturally, our average Cocoa programmer wouldn’t agree with this assertion. For example, Cocoa programmers brag about these wonderful things called NIBs (an ancient acronym for NeXTstep Interface Builder) which we’re told allow user interface objects to be “freeze-dried”. Ever heard of DFM files? Delphi 1.0 has had ‘em since 1995. OK, I’ll concede that NeXTstep and NIBs have been around for even longer than that, but the essential point is that Delphi, C#, (even VB.NET!) achieve much better synergy between code and form design than does Cocoa.
There’s a whole bunch of other stuff I could talk about here, such as the component-based architecture of Delphi and .NET, which compares starkly with the monolithic nature of Cocoa, but hopefully you’re getting my drift. I’m a big fan of the Mac, and I’m a big fan of much of the intuitive, powerful but easy-to-use software that’s available for OS X. But more than all that, I’m a huge fan of the dedicated Mac developers who have achieved so much with – frankly – so little.
If you’re a dedicated Cocoa-head, you’ve probably had it drilled into you that Cocoa is your “secret weapon”. Compared to Carbon, it certainly is. But everything’s relative, and I’m really looking forward to seeing what the Mac community can achieve when they finally get some decent development tools. When will Interface Builder and XCode finally tie the knot? Not in Leopard, for sure, but maybe in what comes next? Here’s hoping…
Now if you'll excuse me, I have a killer Mac application to write…