Sunday, January 21, 2007

Learning Cocoa: Which Frameworks to Learn?

I've been wondering which frameworks on Mac OS X I should learn. It's hard to know the answer to this, since different applications will need different frameworks. But it occurred to me that examining the frameworks that Apple uses in their own applications might be a good start.

Not too surprisingly, you can determine the shared libraries used by an application. So I whipped up a little shell script to go through a set of applications and print every framework used and the number of different applications that use it. The applications are:

  • Address Book
  • Automator
  • Backup
  • Calculator
  • Chess
  • DVD Player
  • Dashboard
  • Dictionary
  • Font Book
  • GarageBand
  • Image Capture
  • Mail
  • Photo Booth
  • Preview
  • QuickTime Player
  • Safar
  • System Preferences
  • TextEdit
  • iCal
  • iChat
  • iDVD
  • iMovie HD
  • iPhoto
  • iSync
  • iTunes
  • iWeb
  • Keynote
  • Pages

There are more than 100 frameworks used by these applications! Wow. This little experiment reveals some unsurprising things: learn Cocoa. But it also suggests that there are at least portions of Carbon that are required reading (the Carbon framework is the second highest used). There are some odd things near the top, like iMovieSupport.framework and some things that are obviously important but I don't know what they contain (like CoreServices.framework).

If we arbitrarily remove all the frameworks used only once, we still have 71 frameworks. If we remove those used 2 times or less, we still have 61. If we remove all that are used less than 10 times, we end up with 18 frameworks:

100 - Cocoa.framework
93 - Carbon.framework
50 - QuickTime.framework
48 - CoreServices.framework
35 - Foundation.framework
33 - OpenGL.framework
33 - CoreFoundation.framework
30 - iMovieSupport.framework
27 - AppKit.framework
24 - ApplicationServices.framework
24 - AppleAppSupport.framework
21 - IOKit.framework
17 - SystemConfiguration.framework
16 - QuartzCore.framework
13 - Security.framework
13 - AddressBook.framework
11 - QTKit.framework
10 - BDControl.framework

This is much better than 100, but still too large. I guess I need to figure out what is in these libraries and go from there. Until I can do that, I have plenty to do just learning Cocoa fundamentals and the development tools.

Learning Cocoa: Peeling the Currency Converter Onion

Well, after quite a bit of reading and trying to puzzle out how to use Interface Builder to work on applications using Cocoa Bindings, I've concluded that I don't understand well enough. This is rather surprising to me, since I have more than twenty years of development experience with more than fifteen years of object-oriented and GUI programming experience. But whether I'm in the early stages of dementia or Apple's documentation leaves something to be desired, I clearly have to take a different approach :-). So, I've gone back to the Currency Converter tutorial to try to make a few things gel.

I know that Xcode 3.0 and a brand spanking new version of Interface Builder are due out with Leopard sometime this spring (of 2007), but I'm trying to learn as much as I can before then. After the new Xcode and Interface Builder come out, I may revisit this subject to weigh in on the dementia versus documentation debate.

I should point out that this article is not meant to be a slam of Xcode & Interface Builder. I don't have enough knowledge to know if it's my ignorance that is the issue, if Xcode & Interface Builder need improvements, or (probably most likely) some mix of the two. So, this is as much notes to myself for future reference as anything else, posted somewhere that others might find it helpful.

So, time to get started. Happily, the tutorial is pretty up-to-date:
warning about using Mac OS X 10.4 and Xcode 2.2 or later
You'd better be up to date

[Note: This is a discussion of the tutorial and in no way takes the place of the tutorial. You probably need to have worked through the tutorial or work on it in in parallel.]

We are going to create a simple currency converter, to understand how Cocoa implements the MVC (Model/View/Controller) design pattern. The application itself is trivial:

The GUI for the Currency Converter Tutorial Application

After running the Xcode application and creating a "Cocoa Application" project, we see this:

The Main Xcode Window

We are instructed to open the NIB file, named MainMenu.nib, which is the file that contains the user interface. The user interface is edited using Interface Builder, Apple's sort-of WYSIWYG GUI builder. If we double-click on MainMenu.nib, Interface Builder is launched. The tutorial walks us through a number of user interface tasks like renaming menus and menu items, titling the window, creating user interface elements, etc. All of these are simply until we get to creating some bindings.

Even the first binding action, setting up the tab order of the text items is reasonably straightforward. We control-drag from the starting field to the next field. This brings up the object inspectors Connections tab where we choose nextKeyView.

Specifying Tab Order of Text Fields

The strange part, at least to me, is how we specify the first text field to receive focus. In the object window of the NIB, we see this:

There's the item named "First Responder" staring us in the face. But we don't touch it. Instead, we control-drag from the main window to the first text field to recieve keyboard input and choose initialFirstResponder:

Setting the Main Window's "initial responder"

This is non-obvious step number one.

Next, you have to remember you need a custom controller and how to create one. I had no problem with this when I went through the tutorial because it gave me the steps. But when I went to write my own application, I forgot that you have to switch to the Classes tab of the NIB window, select the class you want to sub-class (NSObject in this case), and hit ente r. As it turns out, you can also use the contextual menu to create the sub-class:

Regardless of whether you use the menu (remembering it exists) or hit enter, this is only obvious with practice, giving us non-obvious step number two.

For a complete newbie like myself, knowing what to sub-class is non-obvious, leading to non-obvious step number three. The tutorial tells us to sub-class NSObject, so we do so, naming the new class ConverterController.

Creating the ConverterController class

The tutorial now goes on to talk about outlets. When they are first brought up, their purpose and the reason for giving them a unique name is not obvious. After reading through this again, it now seems clear that outlets are really just object references. They are marked in the code with the IOOutlet macro, a null macro apparently there solely to let Interface builder find them in the code. But things get more confusing quickly. The next section telegraphs the murkiness to come. The first sentence in the "Target/Action in Interface Builder" section says:

"You can view (and complete) target/action connections in the Connections pane in the Interface Builder inspector. This pane is easy to use, but the relation of target and action in it might not be apparent."

After introducing the new term "target/action connections", in the very next sentence they define a target as the outlet of a cell that sends an action message. What the heck is a cell and what is an action message? The next few paragraphs weren't particularly helpful in explaining this.

After some additional reading and head-scratching, I think it's much simpler than they made it. UI components like buttons have their own object references ("outlets") that refer to things, and they use those references to invoke methods ("actions") on the object they refer to. It's a stinkin' object reference used to invoke a method. I honestly still have no idea what a "cell" is, but I'm betting it has to do with some abstract pattern of the UI components of the Cocoa GUI frameworks that I really don't need to know about at this point. There is one subtle bit of information buried in here: "actions" follow a naming pattern (again, to let Interface Builder find them). I wish they'd just told us that from the outset.

So now I think I finally get it: start your control-drag from the object that will do the invoking and stop on the thing to be invoked. So if your button needs to invoke the controller because it was clicked, drag from the button to the controller. If your controller needs to alter the model object, drag from the controller to the model object.

Along the way, another non-obvious thing showed up: when you view the instances tab of the NIB window, you don't see the outlets and actions of that instances class. For example, the attributes tab of the inspector is empty:

Inspector Display when Examining Instances

Then, when you switch to the Classes tab and have ConverterController selected, you see the outlets and actions:

Inspector Display when Examining Classes

Don't get me wrong: this is good contextual behavior by the Inspector. But for a newbie it was a revelation when I first noticed that flipping to the Classes tab (where the ConverterController class was already selected) showed the outlets and actions I'd defined a few minutes ago and lost track of. I think a lot of this is due to trying to absorb all the new terms in the first place, leaving me dazed and confused...

The next several pages of the tutorial are reasonably straightforward, describing how to add required methods and providing the code for those methods. There's a fair bit of Objective-C, but nothing shocking to someone who understands OO.

After some housekeeping and doing a build, I was able to run my application. And of course it didn't work.
Prior to taking the time to write this down, I would have been at a loss at this point. But by forcing myself to (mostly?) sort out the whole "outlet"/"action"/"connection" business, I had enough information that I quickly figured out I'd somehow deleted the connection from my ConverterController to my Converter. Once I reconnected them, the application started working.

Getting zero feedback when I clicked and the text window for the run produce is a real issue. I understand the need to not flood a console with messages in a real application. And I realize a production GUI application may have nowhere to send messages. But Xcode has a window with text output for the session when you run the application:

The Run Log Window of Xcode

It only seems natural, especially when running the debug version, to print some error messages indicating where my problem manifested. I hope someone can tell me a simple way to turn on what should have been on by default.

Learning Cocoa: Links

I'm starting to spend more time trying to learn the Cocoa development frameworks. For those not familiar with it, Cocoa is a set of software development frameworks based around the Objective-C programming language. There are a number of different frameworks within Cocoa, including GUIs, networking (and IO in general), graphics & imaging, distributed computing, etc.

The most obvious site for learning about Cocoa is the Apple developer website. But, with the help of some friends who are also trying to learn Cocoa, I'm starting to find other good resources on the web for learning Cocoa. Since Cocoa is not as well-known as Java, C++, or Ruby, it's like discovering a whole new world on the web. Here are a few links I'm finding useful:

Cocoa Dev Central - a sort of almanac of Cocoa-related material
Cocoa Blogs - a website listing blogs of people discussing Cocoa (I still need to drill down on this one)
CocoaLab - has a PDF trying to help non-programmers learn how to program Cocoa.
CocoaHeads - "CocoaHeads is a group devoted to discussion of Apple Computer's Cocoa Framework for programming on MacOS X." A sort of clearinghouse for Cocoa Develoer Groups. There's one in St. Louis, so maybe I'll try attending.
IndieHIG - a project to create Human Interface Guidelines (HIG) that are up-to-date with the current Mac OS X look and feel. They feel Apple's guidelines are out-of-date, though the HIG guide on the apple site seems pretty up-to-date to me.
Karelia Software's Cocoa Open Source - "A random collection of useful bits of Cocoa, as found in Watson and in other sundry Karelia applications and testbeds. Feel free to adapt these for use in your Cocoa applications."
Theocacao - a website/blog by Scott Stevenson discussing Cocoa and related topics.

There are even a couple of podcasts on the subject:

Cocoa Radio
Late Night Cocoa

Some of these I found myself, while some of these came from Brian Coyner or David Giovaninni (thanks, guys!).

Searching: Wikipedia as a Primary Source

It's amazing to me how much good material there is on Wikipedia these days. It's getting to the point where I'm about to switch from doing a Google search as my first step in research to doing a Wikipedia search. This obviously doesn't work for very dynamic or overly specific things, like a recent news story (Google News) or some very detailed aspect of a software package. But for terms, or relatively well-known subjects, it is a wealth of information.

For example, it's entry on the Objective-C programming language is quite good. It's explanation of networking terms, for example, is surprisingly good.

It may be time to switch the default search engine for my Safari search field...

Wednesday, January 10, 2007

Splitting the Blog

I've decided to split my blog. I'll use this blog for more 'personal' items, not related to technology. My other blog, View From the Fringe, which has been almost unused since I created it, will be for more technical content.

So if you come here looking for something and can't find it, it may have moved over to the other blog. And if you come here looking for technical material, check out View From the Fringe.

Monday, January 01, 2007

Home Improvement: The Closet Project

I've been working to install built-in, adjustable storage in our closet since late September. It was a fairly large project to tackle, since it would involve building the equivalent of seven bookcases, except the cases were taller (8 feet) and deeper (15 or 22 inches) than normal bookcases. In addition, I planned to build them into the space permanently.

These are some pictures of the closet at the start of the projecxt, when we cleared it out:

A good friend, who is much more knowledgeable about this than I, suggested that I use a very clever system. It involves 5mm holes spaced 32mm apart. The holes can accept small pegs to hold shelves, as is common with adjustable shelf bookcases.

But the holes are also the right size to accept these very Knopf-Vogt hardware brackets:

With two of these brackets, one inserted in each side of the case, it is possible to hang a clothes rod in the case at any height. This allows a "mix and match" approach, where shelves are intermixed with hanging storage at a variety of heights. My friend Dave is very smart (vastly smarter than I'll ever be) about this stuff, and this was the first of many great suggestions he made.

Here's a picture of a bracket with the rod inserted:

This was a fairly challenging project, especially since I built it with melamine (particle board which has had a kind of plastic thermally fused to both surfaces). The overall steps were:

  1. Clean out the room and remove the carpet and pad carefully, so some of it could be re-used later (see pictures above).
  2. Build a 3 inch high base for each side of the closet. Once the base was built and taken to the room, it was very carefully leveled and screwed into place. This provided a stable, level base upon which to place the carcasses. It was time consuming but there is no reliable way to get the carcasses level and even without greater risk and/or time.
  3. Build the pieces of the carcasses, being careful to make everything exactly the right size. This required using a special saw blade in my table saw, which has a negative hook angle. This lets it cut the melamine without creating lots of chips along the edge of the cut.
  4. Cut (almost) all the shelves (since I was set up to cut melamine already).
  5. Take the pieces of each carcass up to the closet to assemble a carcass. This was necessary because the carcasses are so big it would be impossible to fit them through the closet door if they were assembled. I also had to use a special glue, called Roo Glue Clear, that bonds well to the very slick surface of melamine. To screw the carcasses together at top and bottom, I used the Jack Rabbit drilling and screwing system. It is a very clever piece of hardware that lets you drill a hole, including the countersinking recess near the surface. After drilling the hole, you pop off the drill bit to drive the screw. I learned about this watching The New Yankee Workshop. This lets you use one drill for two purposes and not need three hands. This was my first project using it and it was worth every penny I spent on it.
  6. Figure out the spacing of the carcasses relative to each other and to the walls. This was important so that the finish trim pieces could all be the same width. This is a place where my friend Dave saved me. I would not have placed much importance on having the vertical trim pieces (the stiles) be the same width. I even tried having variable width pieces (I cut them to length and put them in place) and they looked terrible.
  7. Mill pieces of poplar the exact thickness needed to glue the carcasses together and to the walls.
  8. Glue strips of wood to the ceiling so they were even with the fronts of the carcasses. This provided a strip to which I could nail the wide rails that run from the edge of each carcass to the ceiling.
  9. Cut and attach the bottom and top rails.
  10. Cut and attach the baseboards. I reused the original baseboards which had been removed at the start of the project, cutting them down from 7 1/2 inches to a bit less than 3 inches.
  11. Cut and attach the stiles between carcasses. This step was particularly tricky, since I was gluing and nailing the stiles and needed to make sure I didn't send a nail through the side of the carcass where it would ruin it.
  12. Make the bead detail that runs around the sides and top of each case opening, cut them to length (mitering corners), and attach them to the inside edge of each opening.

  13. Prime and paint the face frames.
  14. Re-lay the carpet
  15. I was planning to attach strips of poplar to the front of each shelf, but after we had the cases done and we put a shelf into the case (without anything on the front), my wife and I decided it would look better if the shelves were simply banded with melamine across the front. So I bought a 'J' roller, a bunch of melamine edge banding, a cheap iron to activate the glue on the back of the banding, and a veneer trimmer to trim the excess after the banding had cooled.

  16. Cut each of the rods to the right length so they just barely fit into the brackets, making sure they won't slip out of the brackets when hangers are removed (or the rods are bumped).

I tried to re-stretch the carpet in the closet and failed completely. Luckily, a guy that works for the contractor who did work on our house a few years ago knows how to stretch carpet. He doesn't like to do large jobs but he agreed to do this one. He did a great job and after he was done we were ready to clean everything (which took much longer than I'd expected) and install the shelves and rod.

The space exceeded our expectations for flexibility. We were able to adjust shelves and rods easily, and quickly had the space customized for our clothes. The most surprising thing of all: we were able to put all our clothes into the closet, including off-season clothes that were normally stored in rubbermaids in the attic.

It was a challenging project, and I made my share of mistakes (all of which I was able to remove or repair). I learned a lot and I'm glad I did it. But most of all, I'm glad it's done.

I want to extend my eternal gratitude to my friend Dave Aholt. If not for him, this project would have been a disaster from start to finish. This project looks good because of him, and where it looks bad it's because I failed to follow his advice.