Tuesday, October 07, 2008

How Xcode and Interface Builder relate

I'm starting to understand now how Xcode ties in with the Interface Builder.

My first confusion was this: in the main function when UIApplicationMain is created, how can it know what its delegate is when it is not explicitly mentioned in the arguments? Answer: It's mentioned in the MainWindow.xib file. This file is an XML file which is turned into a "nib file" later (when building?). Double clicking on it in Xcode brings up the Interface Builder. Clicking on "file's owner" and then pressing apple-shift-I brings up the Inspector, where I could then see the delegate -› MoveMeAppDelegate relationship (wtf had to press alt-b to get the › character).

Next I'd like to understand how to reference things set from the Interface Builder from my code. Specifically, how to change the text in a label? What identifies the label in my code?

[24 hours pass]

Okay wow, somehow that was really tough to figure out. To change a text in a label, I needed to get a reference to the label object. I was really confused trying to drag a line from "referencing outlet" to somewhere, with nothing accepting the drag. Turns out this is where the IBOutlet comes into play. I had to have IBOutlet UILabel *label; in the class to which I am dragging to, then the drag will be accepted (although at one point I seemed to sense a delay before Interface Builder realized now the drag can be accepted?).

So the controller that accepted a drag from a textfield "referencing outlet" looks like this:

@interface ThreeFieldsViewController : UIViewController {
IBOutlet UILabel *label;
}
@property (nonatomic, retain) IBOutlet UILabel *label;

Then additionally in the .m file I had to @synthesize label. Didn't check if it would work without that. Actually, it would be interesting to test if the Interface Builder code that gets generated just sets the attribute directly, or calls setLabel? Let's see. Yep, setters and getters are called if and only if there is a referencing outlet.

As a bonus I discovered that if you make a method and tag it IBAction, you can drag action references from components to that in Interface Builder. Not sure if there are some interesting arguments passed that could somehow be read. Next up: trying to make an app with three labels that get updated by a timer with data from the accelerometer.