IBOutlet and IBAction

One of the first big confusions I confronted when learning to work with xcode and Interface Builder was the connection between things in my code (particularly those marked as IBOutlets or IBActions) and corresponding things in Interface Builder.  In many languages, you expect every file you work with to be explicitly mentioned by name somewhere in the code base – with xib files, this isn’t always the case – at least not in any obvious way.

The problem

To illustrate the confusion and its solution, let’s explore a quick example:

MainViewController.h

MainViewController.m

This view controller will set up a screen according to its xib file (MainViewController.xib), and modify the label’s text to match the text of any buttons which are pressed.

This is a relatively easy piece of code for a newbie.  If you’re new to Interface Builder (IB), though, you might not know how to correctly connect the UIButtons and UILabel in IB to the instance variable (label) and method (toggleLabel:) for use at runtime.  Below are the steps to do that.

The Solution

1. Make sure you’ve already created the pieces that need to be connected:

  • The instance variables, such as label here, marked with IBOutlet in your header file,
  • the methods that need to be activated by controls, such as toggleLabel: here, marked with the IBAction return type, and
  • the objects, such as UIButtons or UILabels, in Interface Builder that will be connected.

2. Right-click on “File’s Owner” in the MainViewController.xib window, which brings up a list of assignable properties of that object which IB knows about (see the figure below).

3. Click the open circle to the right of label, and drag the blue line that appears over to the UILabel in your working xib area.  This ensures that the instance variable label will point to this UILabel when it’s created for you at runtime.

4. Next connect buttons to actions.  Drag from the open circle next to toggleLabel: over to one of the UIButtons (e.g. the tree button in the figure).

5. A UIButton generates many events, although the primary one is called “Touch Up Inside” (insert dirty joke here), which essentially means the user pushed the button.  Interface Builder doesn’t complete the connection between the button and your method until you specify which action you mean – and 99% of the time with buttons, you just care about the Touch Up Inside action, so choose that one.

6. Repeat the same process for any other buttons you want to connect with this method (toggleLabel:).  Note that you can connect as many controls as you want to a single method (IBAction), although you can only connect a single control to an instance variable (IBOutlet), which makes perfect sense from the perspective of the code.

7. Celebrate!  Good job.

How it works

From the compiler’s point of view, an IBAction is just the void return type, and IBOutlet is ignored.  The compiler more-or-less doesn’t know about those terms.

But they are very significant for Interface Builder.  IB knows about your code, and it recognizes those terms as marking variables and methods that can be connected to objects in a xib file, just as we’ve done here.

How does it work at runtime?  Essentially, UIViewController, as the superclass of MainViewController, knows to look for a file named “MainViewController.xib.”  Yes, the correspondence is actually determined by matching a filename against the name of the class (and, yes, this feels a little hacky to me, although I admit it’s very convenient).  If that xib file exists, the view in it is created with all the properties (positioning, fonts, strings, colors, connections, etc) at runtime.  If you have many UILabels in your view, and many instance variables pointing to UILabels, then the code that creates these views for you will need to know which pointers are meant to point to which objects – that’s why we need to provide these connections.  The information for those connections is stored in the xib file, which the UIViewController code handles for you.

There are a lot more interesting details behind the curtains, but that is the subject of another post.

2 Comments