Nib Management - IDE - iOS 7 Programming Fundamentals: Objective-C, Xcode, and Cocoa Basics (2014)

iOS 7 Programming Fundamentals: Objective-C, Xcode, and Cocoa Basics (2014)

Part II. IDE

Chapter 7. Nib Management

The term nib file, or simply nib, has nothing to do with fountain pens or bits of chocolate; it originated as an acronym for “NeXTStep Interface Builder”, which was used for the .nib file extension. Just about any iOS app you create will contain at least one nib file. This file will be generated from either a .xib file or a .storyboard file in your Xcode project (see Chapter 6). When you edit a .xib or .storyboard file in Xcode, you appear to be in a drawing program; it looks as if you’re designing a piece of interface graphically, much as you might create and edit a drawing in Adobe Illustrator, OmniGraffle, Canvas, or any of a host of other similar drawing applications past and present. I’ll refer to this aspect of Xcode’s editing environment as the nib editor.

NOTE

Up through Xcode 3.2.x, nib editing was performed in a separate application, Interface Builder. Starting in Xcode 4, the functionality of Interface Builder was rolled into Xcode itself. Nevertheless, the nib editor environment within Xcode is still often referred to as Interface Builder.

When you work in the nib editor, you’re not really creating a drawing. You’re encoding instructions for instantiating, initializing, and configuring objects. As I said in Chapter 5 (see especially Nib-Based Instantiation), when you drag a button into a view in the nib editor, put that button into a certain position, give it a certain size, and double-click it and set its title to “Howdy!”, you’re putting instructions into the nib that will generate a UIButton instance and set its frame and title properties and make it a subview of the view you dragged it into, much as if you had performed the entire process of instantiation, initialization, and configuration of that button in code such as this:

UIButton* b =

[UIButton buttonWithType:UIButtonTypeSystem]; // instantiate

[b setTitle:@"Howdy!" forState:UIControlStateNormal]; // set up title

[b setFrame: CGRectMake(100,100,52,30)]; // set up frame

[self.view addSubview:b]; // put into view

The instructions that you create by working in the nib editor are embodied in a nib file in the built app. These instructions are effectively a collection of potential objects, also referred to as nib objects. Those potential objects encoded in the nib are not turned into real objects until and unless the nib is loaded in the course of the app’s running. At that moment, the instructions embodied in the nib file are obeyed by the nib-loading mechanism, and the objects are reproduced into living instances, ready to become part of your running app. They are mostly interface objects, so the way in which they will usually manifest themselves is by being made subviews of a view that the user will see.

Thus there are three stages in the life of a nib with which you will be concerned while programming iOS:

§ How to edit the nib as a .xib or .storyboard file in Xcode

§ How the nib will come to be loaded as the app runs

§ How, when the nib is loaded, the app will use the instances that it generates

These, and related matters, are the concerns of this chapter.

ARE NIBS NECESSARY?

Since nibs are ultimately just sources of instances, you might wonder whether it is possible to do without them. Those same instances could be generated in code, so wouldn’t it be possible to dispense with nibs altogether? The simple answer is: Yes, it would. It’s quite possible to write a complex app that lacks a single .storyboard or .xib file (I’ve done it). The practical question, however, is one of balance. Most apps use nib files as a source of at least some interface objects; but there are some aspects of interface objects that can be customized only in code, and sometimes it’s easier to generate those interface objects entirely in code at the outset. In real life your projects will probably involve a great deal of interplay between code and nib-generated objects.

A Tour of the Nib Editor Interface

Let’s explore Xcode’s nib editor interface. In Chapter 6, we created a simple iPhone project, Empty Window, directly from the Single View Application template; it contains a storyboard file, so we’ll use that. In Xcode, open the Empty Window project, locate Main.storyboard in the Project navigator, and click to edit it.

Editing a nib file

Figure 7-1. Editing a nib file

Figure 7-1 shows the project window after selecting Main.storyboard and making some additional adjustments. The Navigator pane is hidden; the Utilities pane is showing, containing the Size inspector and the Object library. The interface may be considered in four pieces:

1. At the left of the editor is the document outline, listing the storyboard’s contents hierarchically by name. It can be hidden by dragging its right edge or by clicking the left-pointing-triangle button that sits near its bottom right corner.

2. The remainder of the editor is devoted to the canvas, where you physically design your app’s interface. The canvas portrays views in your app’s interface and things that can contain views. A view is an interface object, which draws itself into a rectangular area. The phrase “things that can contain views” is my way of including view controllers, which are represented in the canvas even though they are not drawn in your app’s interface; a view controller isn’t a view, but it has a view (and controls it).

3. The inspectors in the Utilities pane let you edit details of the currently selected object.

4. The libraries in the Utilities pane, especially the Object library, are your source of interface objects to be added to the nib.

The Document Outline

The document outline portrays hierarchically the relationships between the objects in the nib. This structure differs slightly depending on whether you’re editing a .storyboard file or a .xib file.

In a storyboard file, the primary constituents are scenes. A scene is, roughly speaking, a single view controller, along with some ancillary material; every scene has a single view controller at its top level.

A view controller isn’t an interface object, but it manages an interface object, namely its view (or main view). A view controller in a nib doesn’t have to have its main view in the same nib, but it usually does, and in that case, in the nib editor, the view usually appears inside the view controller in the canvas. Thus, in Figure 7-1, the large blue-highlighted rectangle in the canvas is a view controller’s main view, and it is actually inside a view controller. The view controller itself is represented in the canvas by the rectangle containing the view, along with the black rounded rectangle below it, which is called the scene dock. This is easier to see if the view controller itself is selected, as in Figure 7-2: the view controller and its scene dock are highlighted together, with a heavy blue outline.

A view controller selected in a storyboard

Figure 7-2. A view controller selected in a storyboard

Each view controller in a storyboard file, together with its view and its scene dock, constitutes a scene. This scene is also portrayed as a hierarchical collection of names in the document outline. At the top level of the document outline are the scenes themselves. At the top level of each scene are names that designate the objects in the view controller’s scene dock: the view controller itself, along with two proxy objects, the First Responder token and the Exit token. These objects — the ones displayed as icons in the scene dock, and shown at the top level of the scene in the document outline — are the scene’s top-level objects.

Objects listed in the document outline are of two kinds:

Nib objects

The view controller, along with its main view and any subviews that we care to place in that view, are real objects — potential objects that will be turned into actual instances when the nib is loaded by the running app. Such real objects to be instantiated from the nib are also called nib objects.

Proxy objects

The proxy objects (here, the First Responder and Exit tokens) do not represent instances that will come from the nib when it is loaded. Rather, they represent other objects, and are present to facilitate communication between nib objects and other objects (I’ll give examples later in this chapter). You can’t create or delete a proxy object; the nib editor shows them automatically.

Aside from the top-level objects, most objects listed in a storyboard’s document outline will depend hierarchically upon a scene’s view controller. For example, in Figure 7-1, the view controller has a main view; that view is listed as hierarchically dependent on the view controller. That makes sense, because this view belongs to this view controller. Moreover, any further interface objects that we drag into the main view in the canvas will be listed in the document outline as hierarchically dependent on the view. That makes sense, too. A view can contain other views (its subviews) and can be contained by another view (its superview). One view can contain many subviews, which might themselves contain subviews. But each view can have only one immediate superview. Thus there is a hierarchical tree of subviews contained by their superviews with a single object at the top. The document outline portrays that tree (as an outline!).

In a .xib file, there are no scenes. What would be, in a .storyboard file, the top-level objects of a scene become, in a .xib file, the top-level objects of the nib itself. Nor is there any requirement that one of these top-level objects be a view controller; it can be, but more often the top-level interface object of a .xib file is a view. It might well be a view that is to serve as a view controller’s main view, but that’s not a requirement either. Figure 7-3 shows a .xib with a structure parallel to the single scene of Figure 7-1.

A .xib file containing a view

Figure 7-3. A .xib file containing a view

The document outline in Figure 7-3 lists three top-level objects. Two of them are proxy objects, termed Placeholders in the document outline: the File’s Owner, and the First Responder. The third is a real object, a view; it will be instantiated when the nib is loaded as the app runs. The document outline in a .xib file can’t be completely hidden; instead, it is collapsed into a set of icons representing the nib’s top-level objects, similar to a scene dock in a storyboard file, and often referred to simply as the dock (Figure 7-4).

The dock in a .xib file

Figure 7-4. The dock in a .xib file

At present, the document outline may seem unnecessary, because there is very little hierarchy; all objects in Figure 7-1 and Figure 7-3 are readily accessibly in the canvas. But when a storyboard contains many scenes, and when a view contains many levels of hierarchically arranged objects (along with their autolayout constraints), you’re going to be very glad of the document outline, which lets you survey the contents of the nib in a nice hierarchical structure, and where you can locate and select the object you’re after. You can also rearrange the hierarchy here; for example, if you’ve made an object a subview of the wrong view, you can reposition it within this outline by dragging its name. You can also select objects using the jump bar at the top of the editor: the last jump bar path component (Control-6) is a hierarchical pop-up menu similar to the document outline.

If the names of nib objects in the document outline seem generic and uninformative, you can change them. The name is technically a label, and has no special meaning, so feel free to assign nib objects labels that are useful to you. Select a nib object’s label in the document outline and press Return to make it editable, or select the object and edit the Label field in the Document section of the Identity inspector (Command-Option-3).

Canvas

The canvas provides a graphical representation of a top-level interface nib object along with its subviews, similar to what you’re probably accustomed to in any drawing program. In a .xib file, you can remove the canvas representation of a top-level nib object (without deleting the object) by clicking the X at its top left (Figure 7-3), and you can restore the graphical representation to the canvas by clicking that nib object in the document outline. The canvas is scrollable and automatically accommodates however many graphical representations it contains; a storyboard canvas can also be zoomed (choose Editor → Canvas → Zoom, or use the zoom buttons at the lower right of the canvas; Figure 7-1).

Our simple Empty Window project’s Main.storyboard contains just one scene, so it represents graphically in the canvas just one top-level nib object — the scene’s view controller. Inside this view controller, and generally indistinguishable from it in the canvas, is its main view. It happens that this view controller will become our app’s window’s root view controller when the app runs; therefore its view will occupy the entire window, and will effectively be our app’s initial interface (see Chapter 6). That gives us an excellent opportunity to experiment: any visible changes we make within this view should be visible when we run the app. To prove this, let’s add a subview:

1. Start with the canvas looking more or less like Figure 7-1.

2. Look at the Object library (Command-Option-Control-3). If it’s in icon view (a grid of icons without text), click the button at the left of the filter bar to put it into list view. Type “button” into the filter bar, so that only button objects are shown in the list. The Button object is listed first.

3. Drag the Button object from the Object library into the view controller’s main view in the canvas (Figure 7-5), and let go of the mouse.

Dragging a button into a view

Figure 7-5. Dragging a button into a view

A button is now present in the view in the canvas. The move we’ve just performed — dragging from the Object library into the canvas — is extremely characteristic; you’ll do it often as you design your interface.

Much as in a drawing program, the nib editor provides features to aid you in designing your interface. Here are some things to try:

§ Select the button: resizing handles appear. (If you accidentally select it twice and the resizing handles disappear, select the view and then the button again.)

§ Using the resizing handles, resize the button to make it wider: dimension information appears.

§ Drag the button near an edge of the view: a guideline appears, showing a standard margin space between the edge of the button and the edge of the view. Similarly, drag it near the center of the view: a guideline shows you when the button is centered.

§ With the button selected, hold down the Option key and hover the mouse outside the button: arrows and numbers appear showing the distance between the button and the edges of the view. (If you accidentally clicked and dragged while you were holding Option, you’ll now have two buttons. That’s because Option-dragging an object duplicates it. Select the unwanted button and press Delete to remove it.)

§ Control-Shift-click on the button: a menu appears, letting you select the button or whatever’s behind it (in this case, the view, as well as the view controller because the view controller acts as a sort of top-level background to everything we’re doing here).

§ Double-click the button’s title. The title becomes editable. Give it a new title, such as “Howdy!”

To prove that we really are designing our app’s interface, we’ll run the app:

1. Examine the Debug → Activate / Deactivate Breakpoints menu item. If it says Deactivate Breakpoints, choose it; we don’t want to pause at any breakpoints you may have created while reading the previous chapter.

2. Make sure the destination in the Scheme pop-up menu is iPhone Retina (I don’t care whether it’s 3.5-inch or 4-inch).

3. Choose Product → Run (or click the Run button in the toolbar).

After a heart-stopping pause, the iOS Simulator opens, and presto, our empty window is empty no longer (Figure 7-6); it contains a button! You can tap this button with the mouse, emulating what the user would do with a finger; the button highlights as you tap it.

The Empty Window app’s window is empty no longer

Figure 7-6. The Empty Window app’s window is empty no longer

Inspectors and Libraries

Four inspectors appear in conjunction with the nib editor, and apply to whatever object is selected in the document outline, dock, or canvas:

Identity inspector (Command-Option-3)

The first section of this inspector, Custom Class, is the most important. Here you learn, and can change, the selected object’s class. Some situations in which you’ll need to change the class of an object in the nib appear later in this chapter.

Attributes inspector (Command-Option-4)

Settings here correspond to properties and methods that you might use to configure the object in code. For example, selecting our view and choosing from the Background pop-up menu in the Attributes inspector corresponds to setting the view’s backgroundColor property in code. Similarly, selecting our button and typing in the Title field is like calling the button’s setTitle:forState: method.

The Attributes inspector has sections corresponding to the selected object’s class inheritance. For example, the UIButton Attributes inspector has three sections: in addition to a Button section, there’s a Control section (because a UIButton is also a UIControl) and a View section (because a UIButton is also a UIView).

Size inspector (Command-Option-5)

The X, Y, Width, and Height fields determine the object’s position and size within its superview, corresponding to its frame property in code; you can equally do this in the canvas by dragging and resizing, but numeric precision can be desirable.

If Autolayout is turned off (uncheck Use Autolayout in the File inspector), the Size inspector displays an Autosizing box that corresponds to the autoresizingMask property, along with an animation that demonstrates visually the implications of your autoresizingMask settings; plus, an Arrange pop-up menu contains useful commands for positioning the selected object.

If Autolayout is turned on (the default for new .xib and .storyboard files), the rest of the Size inspector has to do with the selected object’s Autolayout constraints, plus a four-button cartouche at the lower right of the canvas helps you manage alignment, positioning, and constraints.

Connections inspector (Command-Option-6)

I’ll discuss and demonstrate use of the Connections inspector later in this chapter.

Two libraries are of particular importance when you’re editing a nib:

Object library (Command-Option-Control-3)

This library is your source for objects that you want to add to the nib.

Media library (Command-Option-Control-4)

This library lists media in your project, such as images that you might want to drag into a UIImageView — or directly into your interface, in which case a UIImageView is created for you.

Nib Loading

A nib file is a collection of potential instances — its nib objects. Those instances become real only if, while your app is running, the nib is loaded. At that moment, the nib objects contained in the nib are transformed into instances that are available to your app.

This architecture is a source of great efficiency. A nib usually contains interface; interface is relatively heavyweight stuff. A nib isn’t loaded until it is needed; indeed, it might never be loaded. Thus this heavyweight stuff won’t come into existence until and unless it is needed. In this way, memory usage is kept to a minimum, which is important because memory is at a premium in a mobile device. Also, loading a nib takes time, so loading fewer nibs at launch time — enough to generate just the app’s initial interface — makes launching faster.

NOTE

Nib loading is a one-way street: there’s no such thing as “unloading” a nib. As a nib is loaded, its instances come into existence, and the nib’s work, for that moment, is done. Henceforward it’s up to the running app to decide what to do with the instances that just sprang to life. It must hang on to them for as long as it needs them, and will let them go out of existence when they are needed no longer.

Think of the nib file as a set of instructions for generating instances; those instructions are followed each time the nib is loaded. The same nib file can thus be loaded numerous times, generating a new set of instances each time. For example, a nib file might contain a piece of interface that you intend to use in several different places in your app. A nib file representing a single row of a table might be loaded a dozen times in order to generate a dozen visible rows of that table.

Recall from Chapter 5 that instances come about in three ways: as ready-made instances (through a method call that vends an instance), by instantiation from scratch (by calling alloc), and through the loading of a nib. We are now ready to discuss this third way of making instances.

Here are some of the chief circumstances under which a nib file is commonly loaded while an app is running:

A view controller is instantiated from a storyboard

A storyboard is a collection of scenes. Each scene starts with a view controller. When that view controller is needed, it is instantiated from the storyboard. This means that a nib containing the view controller is loaded.

Most commonly, a view controller will be instantiated from a storyboard automatically. For example, as your app launches, if it has a main storyboard, the runtime looks for that storyboard’s initial view controller and instantiates it (see Chapter 6). Similarly, a storyboard typically contains several scenes connected by segues; when a segue is performed, the destination scene’s view controller is instantiated.

It is also possible for your code to instantiate a view controller from a storyboard, manually. You can instantiate the storyboard’s initial view controller by calling instantiateInitialViewController, or any view controller whose scene is named within the storyboard by an identifier string by calling instantiateViewControllerWithIdentifier:.

(Note that this is not the only way in which a view controller can come into existence. Far from it. A view controller is an instance like any other instance, so it can be created by telling a view controller class to instantiate itself. We saw this in Chapter 6, where we created a view controller in our Truly Empty app by saying [ViewController new]. No nib was loaded at that moment; that was instantiation from scratch, not nib-based instantiation.)

A view controller loads its main view from a nib

A view controller has a main view. But a view controller is a lightweight object (it’s just some code), whereas its main view is a relatively heavyweight object. Therefore, a view controller, when it is instantiated, lacks its main view. It generates its main view later, when that view is needed because it is to be placed into the interface. A view controller can obtain its main view in several ways; one way is to load its main view from a nib.

If a view controller belongs to a scene in a storyboard, and if, as will usually be the case, it contains its view in that storyboard’s canvas (as in our Empty Window example project), then there are two nibs involved: the nib containing the view controller, and the nib containing its main view. The nib containing the view controller was loaded when the view controller was instantiated, as I just described; now, when that view controller instance needs its main view, the main view nib is loaded, and the whole interface connected with that view controller springs to life.

In the case of a view controller instantiated in some other way, there may be a .xib-generated nib file associated with it, containing its main view. The view controller will automatically load this nib and extract the main view when it’s needed. This association between a view controller and its main view nib file is made through the nib file’s name, and can happen in one of two ways:

Automatically, based on the name of the view controller’s class

We saw this in our Truly Empty app in Chapter 6. The view controller’s class was ViewController. The .xib file, and hence the nib file, was also called ViewController (ignoring the file extension). That’s enough to tell the nib-loading mechanism where to find the view controller’s main view nib file when it’s needed.

Explicitly, through the view controller’s nibName property

When a view controller is instantiated, if it is initialized with initWithNibName:bundle:, the name of the nib file containing its main view may be stated explicitly as the nibName: argument; this sets the view controller instance’s nibName property, which is used to locate the nib when the main view is needed. Alternatively, the view controller may set its own nibName property in a custom initializer.

Your code explicitly loads a nib file

Up to now, I’ve been describing situations where a nib file is loaded automatically. If a nib file comes from a .xib file, however, your code can also load it manually, by calling one of these methods:

loadNibNamed:owner:options:

An NSBundle instance method. Usually, you’ll direct it to [NSBundle mainBundle].

instantiateWithOwner:options:

A UINib instance method. The nib in question was specified when UINib was instantiated and initialized with nibWithNibName:bundle:.

NOTE

To specify a nib file while the app is running actually requires two pieces of information — its name and the bundle containing it. And indeed, a view controller has not only a nibName property but also a nibBundle property, and the methods for specifying a nib, such as initWithNibName:bundle: and nibWithNibName:bundle:, have a bundle: parameter as well as a name: parameter. In real life, however, the bundle will be the app bundle (or [NSBundle mainBundle], which is the same thing); this is the default, so there will be no need to specify a bundle.

Outlets and the Nib Owner

When a nib loads and its instances come into existence, there’s a problem: those instances are useless. An instance is of no use unless you can get a reference to it (I devoted a section of Chapter 5 to this matter). Without a reference to them, the instances generated by the loading of a nib can’t be used for anything: they can’t be put into the interface; they can’t be modified or further configured; in fact, they can’t even be held on to, and might very well pop right back out of existence again without having served any purpose at all.

One of the main ways of solving this problem is by using an outlet. An outlet is something in a nib file: it’s a connection from one object in a nib file to another. The connection has a direction: that’s why I use the words “from” and “to” to describe it. I’ll call the two objects the source and thedestination of the outlet. The outlet has two aspects:

The outlet’s name

Inside the nib file, the outlet has a name. This name is effectively just a string.

An instance variable in the source’s class

The class of the outlet’s source object has an instance variable (or, what amounts to the same thing, a setter accessor) that matches the outlet’s name (in accordance with the rules of key–value coding, discussed in Chapter 5).

When the nib loads, something unbelievably clever happens. The source object and the destination object are no longer just potential objects in a nib; they are now real, full-fledged instances. The outlet’s name is now immediately used, by key–value coding, to match it with the instance variable (or setter) in the source object, and the destination object is assigned to it.

For example, let’s say that we’ve made a nib where the class of Nib Object A is Dog, and let’s say that a Dog has a master instance variable, which is typed as a Person. And let’s say that the class of Nib Object B is Person. Then:

1. Let’s say that in the nib editor, you draw an outlet connection from Nib Object A (a potential Dog instance) to Nib Object B (a potential Person instance) — an outlet called master. This connection is now part of the nib.

2. The app runs, and somehow this nib loads (in one of the ways I described in the previous section).

3. Nib Object A is instantiated, and Nib Object B is instantiated. We now have an actual Dog instance and an actual Person instance.

4. But the nib-loading mechanism is not finished. It sees that the nib also contains an outlet from Nib Object A to Nib Object B, called master. Accordingly, it calls setValue:forKey: on the Dog instance, where the key is @"master" and the value is the Person instance. Presto, the Dog instance now has a reference to the Person instance — namely, as the value of its master instance variable!

To sum up: an outlet in the nib is just a name involving two potential objects. But when the nib is loaded, the nib-loading mechanism makes those objects real, and it turns that outlet into an actual reference from one object to the other by way of an instance variable (Figure 7-7).

How an outlet provides a reference to a nib-instantiated object

Figure 7-7. How an outlet provides a reference to a nib-instantiated object

The nib-loading mechanism won’t create an instance variable — that is, it doesn’t cause the source object, once instantiated, to have an instance variable of the correct name if it didn’t have one before. The class of the source object has to have defined an instance variable (or setter accessor)already. Thus, for an outlet to work, preparation must be performed in two different places: in the class of the source object, and in the nib. This is a bit tricky. As we’ll see, Xcode helps you by making it hard for you to create an outlet if the source object class doesn’t have the necessary instance variable. However, it is still possible for you to mess things up, as I’ll explain later in this chapter.

Outlets are a clever way of allowing one object in a nib to get a reference to another object in a nib when those objects are no longer in the nib, but have been turned into real instances. But we still have not yet solved the problem we started with. A nib is going to load, and its objects are going to come into existence. The problem isn’t how nib-instantiated objects can refer to one another (though it’s great that they can do so); the problem is how an instance that already existed before the nib loaded can get a reference to an object that won’t come into existence until after the nib has loaded. Otherwise, the objects generated from within the nib will be able to refer to one another, but nobody else will be able to refer to them, and they will still be useless.

We need a way for an outlet to cross the metaphysical barrier between the world of instances before the nib loads and the set of instances to be generated by the loading of the nib. That way is the nib owner proxy object. I mentioned earlier that your .storyboard or .xib file is populated automatically with some proxy objects, whose purpose I didn’t divulge. Now I’m going to tell you what one of them is for, namely the nib owner proxy. First, you need to know where to find it:

§ In a storyboard scene, the nib owner proxy is the top-level view controller. It is the first object listed for that scene in the document outline, and the first object shown in the scene dock.

§ In a .xib file, the nib owner proxy is the first object shown in the document outline or dock; it is listed under Placeholders as the File’s Owner.

The nib owner proxy is a proxy for an instance that already exists outside the nib at the time that the nib is loaded. When the nib is loaded, the nib-loading mechanism doesn’t instantiate this object; it is already an instance. Instead, it substitutes the real, already existing instance for the proxy as it fulfills any connections that involve the proxy.

For example, suppose now that there is a Person nib object in our nib, but no Dog nib object. Instead, the nib owner proxy object’s class is Dog — and a Dog, you remember, has a master instance variable. Then we can draw a master outlet in the nib editor from the nib owner proxy object (because its class is Dog) to the Person nib object. When the nib loads, the nib-loading mechanism will match the Dog nib owner proxy object with an already existing actual Dog instance, and will set the Person as that instance’s master.

But how does the nib-loading mechanism know which already existing Dog instance is to be matched by the nib owner proxy object for this nib on this particular occasion when it loads? I thought you’d never ask. On every occasion when a nib is to be loaded, that nib is assigned an already existing object to be its owner. It is this already existing owner object that the nib owner proxy object represents within the nib (Figure 7-8).

An outlet from the nib owner proxy object

Figure 7-8. An outlet from the nib owner proxy object

How is the nib assigned an owner? In one of two ways:

§ If your code loads the nib by calling loadNibNamed:owner:options: or instantiateWithOwner:options:, an owner object is specified as the owner: argument.

§ If a view controller instance loads a nib automatically in order to obtain its main view, the view controller instance itself is specified as the nib’s owner object.

Let’s focus on the second case, because we already have two projects that demonstrate it. A view controller has a main view. This is expressed formally by the fact that a UIViewController has a view property — which means that, in effect, it has a view instance variable or corresponding accessors (or both). When a view controller loads a nib to get its main view, that view controller (as I just said) is the nib’s owner.

So now we understand how a view controller, as it loads its main view nib, is able to refer to the main view instantiated from it and do something with it (like put it into the interface) — it does it through its view instance variable, which is matched by a view outlet in the nib. The situation is exactly parallel to Figure 7-8, showing the Dog instance that owns the nib with a Dog nib owner proxy that has a master outlet pointing to a Person — except that here we have a UIViewController instance that owns a nib with a UIViewController nib owner proxy that has a view outlet pointing to a UIView. (When I say “UIViewController” and “UIView” here, of course subclasses of these classes will do as well.)

So if a nib is to contain a view controller’s main view, two things had better be true inside that nib:

§ The class of this nib’s nib owner proxy object must be UIViewController, or some subclass thereof — preferably, the class of the view controller that will be loading this nib.

§ This nib must have a view outlet from the nib owner proxy object to the main view nib object.

If both those things are true, all will be well. When the view controller needs its view, it will load the nib with itself as owner; the view described in the nib will come into existence as a full-fledged instance, and the view controller’s view will be a reference to it. This will solve the problem that we set out to solve. All the other instances created from the nib depend upon that main view (as subviews of it, and so forth), so this one view instance variable of the view controller is now a reference to the main view along with the entire kit and caboodle of instances that depend upon it. The view controller is now ready and able to put its view into the interface.

If you look at the projects that we created in Chapter 6, you’ll find that their nibs are indeed set up in just the way I’ve outlined here! First, look at our Empty Window project. Edit Main.storyboard. It has one scene, whose nib owner proxy object is the View Controller object. Select the View Controller in the document outline. Switch to the Identity inspector. It tells us that the nib owner proxy object’s class is indeed ViewController. Now switch to the Connections inspector. It tells us that there is an Outlet connection to the View object (and if you hover the mouse over that outlet connection, the View object in the canvas is highlighted, to help you identify it).

Now look at our Truly Empty project. Edit ViewController.xib. The nib owner proxy object is the File’s Owner placeholder. Select the File’s Owner placeholder. Switch to the Identity inspector. It tells us that the nib owner proxy object’s class is ViewController. Switch to the Connections inspector. It tells us that there is an Outlet connection to the View object.

Creating an Outlet

You will often want to create outlets of your own. To demonstrate how this is done, let’s use the Empty Window project. Earlier in this chapter, we added a button to its initial view controller’s main view. Now let’s create an outlet from the view controller to the button. We propose to call this outlet button.

1. Start by considering the source and destination for this proposed outlet. In the Empty Window project, in Main.storyboard, select, and use the Identity inspector to identify the classes of, the objects involved. The class of the source object is ViewController. The class of the destination object is UIButton. This tells us that the ViewController class is going to need a button instance variable typed as a UIButton* (or some superclass of UIButton).

2. Now we’ll make it so. Edit ViewController.h. Inside the @interface section, enter this line of code:

@property IBOutlet UIButton* button;

That’s a property declaration. I haven’t discussed property declarations yet (the details will appear in Chapter 12), so you’ll just have to take my word that this will work — that it effectively equates to declaring an instance variable and accessor methods for it, in a single line. It isn’t exactly the declaration I’d use in real life, but it will do for now. The key term here is IBOutlet; that’s a hint to Xcode itself, a request saying that you’d like to be able to use this property as the name of an outlet when the source is a ViewController instance. The term IBOutlet is linguistically legal because, although Xcode can see the hint in your code, the compiler will treat it as equivalent to an empty string.

3. Edit Main.storyboard once again. Select View Controller and switch to the Connections inspector. An amazing thing has happened — there is now a button outlet listed here! That’s because we used the magic word IBOutlet in our property declaration in the ViewController class. However, this outlet isn’t yet hooked up to anything. In other words, the Connections inspector is telling us that the selected object (the View Controller) can be the source of a button outlet, but we have not in fact made it the source of a button outlet in this nib. To do so, drag from the circle, to the right of the word button in the Connections inspector, to the button — either the button in the canvas or its name in the document outline. A kind of stretchy line symbolizing the connection follows the mouse as you drag, and the button will be highlighted when the mouse is over it. At that moment, let go of the mouse (Figure 7-9).

Connecting an outlet from the Connections inspector

Figure 7-9. Connecting an outlet from the Connections inspector

The Connections inspector now reports that the button outlet is connected to our button. That’s good, but we have not done anything to prove that this is the case. We have made an outlet, but we are not using the outlet for anything.

How can we use the outlet? Well, if our outlet is properly set up, then when our code runs, after our ViewController’s main view is loaded from the nib, its button property will be a reference to the button that was instantiated from the nib and is now in the app’s visible interface. So let’s write some code that uses that button property to change something about that button. As the button is in the interface, we should be able to see the evidence of our change. We’ll change the button’s title:

1. Edit ViewController.m.

2. The viewDidLoad method runs after the view controller instance has obtained its main view. In this case, that means it will have loaded the nib containing its main view. That’s the nib where we just created the button outlet, referring to our button. So by the time code here runs,self.button should point to the actual button that’s in our interface. Insert this line into the viewDidLoad method:

[self.button setTitle:@"Hi!" forState:UIControlStateNormal];

3. Build and run the project. Sure enough, even though the button says “Howdy!” in the storyboard, it says “Hi!” in the app’s visible interface. Our outlet is working!

Misconfiguring an Outlet

Setting up an outlet to work correctly involves several things being true at the same time. I guarantee that at some point in the future you will fail to get this right, and your outlet won’t work properly. Don’t be offended, and don’t be afraid; be prepared! This happens to everyone. The important thing is to recognize the symptoms so that you know what’s gone wrong.

Wrong source class

Start with our working Empty Window example. Edit the storyboard. Use the Identity inspector to change the class of the scene’s view controller to UIViewController. Run the project. We crash at launch time: “UIViewController … class is not key value coding-compliant for the key button.”

The wrong class is being instantiated as the outlet’s source: instead of ViewController, we’re making a UIViewController instance. UIViewController, the built-in superclass of ViewController, has no button property (no button instance variable, no setButton: setter method). When we load the second nib to obtain the view controller’s main view, it contains an outlet named button. The runtime can’t match that up with anything in the outlet’s source — the UIViewController instance — and we crash.

No instance variable in the source class

Fix the problem from the previous example by using the Identity inspector to change the class of the scene’s view controller back to ViewController. Run the project to prove that all is well. Now comment out the @property declaration in ViewController.h; also comment out theself.button line in ViewController.m. Run the project. We crash at launch time: “ViewController … class is not key value coding-compliant for the key button.”

This is obviously the same problem in a different guise. We are instantiating the right class for the outlet’s source, namely ViewController. But after having created an outlet named button in the nib, we have gone behind the nib editor’s back and removed the corresponding instance variable from the outlet source’s class. Again, when the nib loads, the runtime can’t match the outlet’s name with anything in the outlet’s source — the ViewController instance — and we crash.

No outlet in the nib

Fix the problem from the previous example by uncommenting the line you commented out in ViewController.h and the line you commented out in ViewController.m. Run the project to prove that all is well. Now edit the storyboard. Select the view controller and, in the Connections inspector, disconnect the button outlet by clicking the X at the left end of the second cartouche. Run the project. The app runs, but the button’s title is still “Howdy!” — our attempt to change it to “Hi!” in ViewController’s viewDidLoad method is failing silently.

This one is particularly insidious, and unbelievably common. We’ve set up the source object’s class with the correct instance variable, and the nib editor is listing the outlet, but the outlet has no destination object. The result is that after the nib loads, the source object’s button instance variable is nil. We then refer to self.button but it is nil. We send it the setTitle:forState: message, but this is a message to nil. Messages to nil don’t cause any error, but they don’t do anything either (see Chapter 3).

No view outlet

For this one, you’ll have to use the Truly Empty example, because the storyboard editor guards against it. In the Truly Empty project, edit the .xib file. Select the File’s Owner proxy object, switch to the Connections inspector, and disconnect the view outlet. Run the project. We crash at launch time: “loaded the ‘ViewController’ nib but the view outlet was not set.”

The console message says it all. A nib that is to serve as the source of a view controller’s main view must have a connected view outlet from the view controller (the nib owner proxy) to the view.

WARNING

A view controller has a view outlet because UIViewController’s view property is marked as an outlet. Unfortunately, you can’t see that marking. Nothing in the documentation for a built-in Cocoa class tells you which of its properties are also available as outlets! In general, the only way to learn what outlets a built-in class provides is to examine a representative of that class in the nib editor.

Deleting an Outlet

Deleting an outlet coherently — that is, without causing one of the problems described in the previous section — involves working in several places at once, just as creating an outlet does. I recommend proceeding in this order:

1. Disconnect the outlet in the nib.

2. Remove the outlet declaration from the code.

3. Attempt compilation and let the compiler catch any remaining issues for you.

Let’s suppose, for example, that you decide to delete the button outlet from the Empty Window project. You would follow the same three-step procedure that I just outlined:

1. Disconnect the outlet in the nib. To do so, edit the storyboard, select the source object (the view controller), and disconnect the button outlet in the Connections inspector by clicking the X.

2. Remove the outlet declaration from the code. To do so, edit ViewController.h and delete or comment out the @property declaration line.

3. Remove other references to the property. The easiest way is to attempt to build the project; the compiler issues an error on the line referring to self.button in ViewController.m, because there is now no such property. Delete or comment out that line, and build again to prove that all is well.

More Ways to Create Outlets

Earlier, we created an outlet by manually declaring a property in a class’s header file, and then dragging from the outlet’s circle in the Connections inspector in the nib editor to connect the outlet. Xcode provides many other ways to create outlets — too many to list here. I’ll survey some of the most interesting.

Start by deleting the outlet in our Empty Window project (if you haven’t already done so). Instead of using the Connections inspector to specify the outlet in the nib, we’ll use the HUD (heads-up display) attached to the destination object:

1. In ViewController.h, create (or uncomment) the property declaration:

@property IBOutlet UIButton* button;

2. In the storyboard, Control-drag from the view controller itself to the button. The view controller is represented either by its label in the document outline (View Controller) or by the first icon in the scene dock. The button is represented either by its label in the document outline or by its graphical representation in the canvas.

3. When you release the mouse, a HUD appears, listing button as a possible outlet (Figure 7-10). Click button.

Connecting an outlet by Control-dragging from the source object

Figure 7-10. Connecting an outlet by Control-dragging from the source object

Again, delete the outlet. This time, we’ll start in the HUD attached to the source object:

1. In ViewController.h, create (or uncomment) the property declaration.

2. Control-click the view controller. The view controller is represented either by its label in the document outline (View Controller) or by the first icon in the scene dock. A HUD appears, looking a lot like the Connections inspector.

3. Drag from the circle to the right of button to the button (Figure 7-11). Release the mouse.

Connecting an outlet by dragging from the source object’s HUD

Figure 7-11. Connecting an outlet by dragging from the source object’s HUD

Again, delete the outlet. This time, we’ll start with the HUD attached to the destination object:

1. In ViewController.h, create (or uncomment) the property declaration.

2. Control-click the button. A HUD appears, looking a lot like the Connections inspector.

3. Locate the listing that says New Referencing Outlet. This means an outlet from something else to the thing we’re inspecting, the button. Drag from the circle at its right to the view controller.

4. A second HUD appears, listing outlet names from the view controller. Click button.

Again, delete the outlet. Now we’re going to create the outlet by dragging between the code and the nib editor. This will require that you work in two places at once: you’re going to need an assistant pane. In the main editor pane, show ViewController.h. In the assistant pane, show the storyboard, in such a way that the button is visible.

1. In ViewController.h, create (or uncomment) the property declaration.

2. To the left of the property declaration, a circle appears in the gutter.

3. Drag from that circle across the pane boundary to the button in the nib editor (Figure 7-12), and release the mouse.

Connecting an outlet by dragging from code to nib editor

Figure 7-12. Connecting an outlet by dragging from code to nib editor

Again, delete the outlet. This time, we’re going to create the code and connect the outlet, all in a single move! Use the two-pane arrangement from the preceding example.

1. Control-drag from the button in the nib editor across the pane boundary to the empty @interface section of ViewController.h.

2. A HUD offers to Insert Outlet, Action, or Outlet Collection (Figure 7-13). Release the mouse.

3. A popover appears, where you can configure the declaration to be inserted into your code. Configure it as shown in Figure 7-14. Click Connect.

4. The property declaration is inserted into your code, and the outlet is connected in the nib, in a single move.

Creating an outlet by dragging from nib editor to code

Figure 7-13. Creating an outlet by dragging from nib editor to code

Configuring a property declaration

Figure 7-14. Configuring a property declaration

Making an outlet by connecting directly between code and the nib editor is extremely cool and convenient, but don’t be fooled: there’s no such direct connection. There are always, if an outlet is to work properly, two distinct and separate things — an instance variable in a class, and an outlet in the nib, with the same name and coming from an instance of that class. It is the identity of the names and classes that allows the two to be matched at runtime when the nib loads, so that the instance variable is properly set at that moment. Xcode tries to help you get everything set up correctly, but it is not in fact magically connecting the code to the nib.

When Xcode believes that an outlet is correctly set up, with an appropriate declaration in code and an appropriate connection in a nib, the circle to the left of the declaration in code is filled in. In addition to serving as a sign to you that the outlet should be working, you can click the filled circled to summon a pop-up menu telling you what’s at the other end of the connection: click that menu item and you’re switched to the nib editor, with the destination object selected.

Outlet Collections

An outlet collection is an NSArray instance variable (in code) matched (in a nib) by multiple connections to objects of the same type.

For example, suppose a class contains this property declaration:

@property IBOutletCollection(UIButton) NSArray* buttons;

Note the rather odd syntax: the term IBOutletCollection is accompanied by parentheses containing the name of a class, without an asterisk. The property itself is declared as an NSArray.

The outcome is that, in the nib editor, using an instance of this class as a source object, you can form multiple buttons outlets, each one connected to a different UIButton object in the nib. When the nib loads, those UIButton instances become the elements of the NSArray buttons; the order in which the outlets are formed is the order of the elements in the array.

The advantage of this arrangement is that your code can refer to multiple interface objects instantiated from the nib by number (the index into the array) rather than having to devise and manipulate a separate name for each one. This turns out to be particularly useful when forming outlets to such things as autolayout constraints and gesture recognizers.

Action Connections

In addition to outlet connections in a nib, there are also action connections. An action connection, like an outlet connection, is a way of giving one object in a nib a reference to another.

An action is a message emitted automatically by a Cocoa UIControl interface object (a control), and sent to another object, when the user does something to it, such as tapping the control. The various user behaviors that will cause a control to emit an action message are called events. To see a list of possible events, look at the UIControl class documentation, under “Control Events.” For example, in the case of a UIButton, the user tapping the button corresponds to the UIControlEventTouchUpInside event.

For this architecture to work, the control object must know three things:

§ What control event to respond to

§ What message to send (method to call) when that control event occurs (the action)

§ What object to send that message to (the target)

An action connection in a nib has the control object as its source; its destination is the target, to which the source will send the action message. Configuring the class of the destination object so that it has a method suitable as an action message is up to you.

As an example, let’s arrange to use the view controller in our Empty Window project as a target for an action message emitted by the button’s UIControlEventTouchUpInside event (meaning that the button was tapped). We’ll need a method in the view controller that will be called by the button when the button is tapped. To make this method dramatic and obvious, we’ll have the view controller put up an alert window. Insert this method into the implementation section in ViewController.m:

- (IBAction) buttonPressed: (id) sender {

UIAlertView* av = [[UIAlertView alloc] initWithTitle:@"Howdy!"

message:@"You tapped me."

delegate:nil

cancelButtonTitle:@"Cool"

otherButtonTitles:nil];

[av show];

}

The term IBAction is like IBOutlet: it’s a hint to Xcode itself, and is linguistically legal because, although Xcode can see the hint in your code, the compiler will treat it as equivalent to void. It asks Xcode to make this method available in the nib editor as the selector of an action message, when an object of the class where this method is defined is the destination of an action connection. And indeed, if we look in the nib editor, we find that it is now available: select the View Controller object and switch to the Connections inspector, and you’ll find thatbuttonPressed: is now listed under Received Actions.

As with an outlet connection, constructing an action connection is a two-step process. We have performed the first step: we’ve defined an action method. But we have not yet arranged for anything in the nib to call that method. To do so:

1. Starting in the View Controller object’s Connections inspector, drag from the circle at the right of buttonPressed: to the button. Release the mouse.

2. A HUD listing control events appears. Click Touch Up Inside.

The action connection has now been formed. This means that when the app runs, any time the button gets a Touch Up Inside event — meaning that it was tapped — it will send the action message buttonPressed: to the target, which is the view controller instance. We know what that method should do: it should put up an alert. Try it! Build and run the app, and when the app appears running in the simulator, tap the button. It works!

As with outlet connections, action connections can be formed in many different ways. These are quite parallel to the ways in which outlet connections can be formed. For example, having created the action method in ViewController.m, you can connect the action:

§ By Control-clicking the view controller. A HUD appears, similar to the Connections inspector. Proceed as in the previous case.

§ By selecting the button and using the Connections inspector. Drag from the Touch Up Inside circle to the view controller. A HUD appears, listing the known action methods in the view controller; click buttonPressed:.

§ By Control-clicking the button. A HUD appears, similar to the Connections inspector. Proceed as in the previous case.

It is also possible to connect between the code editor and the nib editor. Arrange to see ViewController.m in one pane and the storyboard in the other. The buttonPressed: method in ViewController.m has a circle to its left, in the gutter. You can drag from that circle across the pane boundary to the button in the nib.

As with an outlet connection, the most impressive way to make an action connection is to drag from the nib editor to your code, inserting the action method and forming the action connection in the nib in a single move. To try this, first delete the buttonPressed: method in your code so that there’s no action connection in the nib. Now:

1. Control-drag from the button in the nib editor to an empty area in the @implementation section of ViewController.m. A HUD offering to Insert Action appears. Release the mouse.

2. A popover view appears, where you configure the action method you’re about to create. Name it buttonPressed:, make sure the Event is set to Touch Up Inside (the default), and click Connect.

Xcode creates a stub method, and forms the corresponding action in the nib, in a single move:

- (IBAction)buttonPressed:(id)sender {

}

The method is just a stub (Xcode can’t read your mind and guess what you want the method to do), so in real life, at this point, you’d insert some functionality between those curly braces.

As with an outlet connection, the filled circle next to the code in an action method tells you that Xcode believes that this connection is correctly configured, and you can click the filled circle to learn what object is (and navigate to) the source of the connection.

NOTE

A nib editor’s Related Files menu includes actions and outlets connected to the currently selected object. This can be a rapid way to navigate, or simply to ascertain what’s at the other end of a connection. An assistant pane, when there’s a nib editor in the main pane, includes the same items in its Tracking menu; thus you can, for example, select an interface object in the nib editor to see instantly in the assistant pane the action method to which it is connected.

CONNECTIONS BETWEEN NIBS

You cannot draw an outlet connection or an action connection between an object in one nib and an object in another nib, or (in a storyboard) between an object in one scene and an object in another scene. If you expect to be able to do this, you haven’t understood what a nib is (or what a scene is, or what a connection is). The reason is simple: objects in a nib together will become instances together, at the moment when the nib loads, so it makes sense to connect them in the nib, because we know what instances we’ll be talking about when the nib loads. If an outlet connection or an action connection were drawn from an object in one nib to an object in another nib, there would be no way to understand what actual future instances the connection is supposed to connect, because they are different nibs and will be loaded at different times (if ever). The problem of communicating between an instance generated from one nib and an instance generated from another nib is a special case of the more general problem of how to communicate between instances in a program, discussed in Chapter 13.

Additional Initialization of Nib-Based Instances

By the time a nib finishes loading, its instances are fully fledged; they have been initialized and configured with all the attributes dictated through the Attributes and Size inspectors, and their outlets have been used to set the values of the corresponding instance variables. Nevertheless, you might want to append your own code to the initialization process as an object is instantiated from a loading nib. This section describes some ways you can do that.

A common architecture is the one we’ve been using throughout this chapter, where a view controller, functioning as the owner when a nib containing its main view loads (and therefore represented in the nib by the nib owner proxy object), has an outlet to an interface object instantiated from the nib. In this architecture, the view controller can perform further configuration on that interface object, because it has a reference to it after the nib loads. The earliest place where it can do this is in its viewDidLoad method. That’s why we used viewDidLoad, earlier in this chapter, as a place to put our code changing the button’s title from “Howdy!” to “Hi!”.

Another possibility is that you’d like the nib object to configure itself, over and above whatever configuration has been performed in the nib. Often, this will be because you’ve got a custom subclass of a built-in interface object class — in fact, you might want to create a custom class, just so you have a place to put this self-configuring code. The problem you’re trying to solve might be that the nib editor doesn’t let you perform the configuration you’re after, or that you have many objects that need to be configured in some identical, elaborate way, so that it makes more sense for them to configure themselves by virtue of sharing a common class than to configure each one individually in the nib editor.

One approach is to implement awakeFromNib in your custom class. The awakeFromNib message is sent to all nib-instantiated objects just after they are instantiated by the loading of the nib: the object has been initialized and configured and its connections are operational.

For example, let’s make a button whose background color is always red, regardless of how it’s configured in the nib. (This is a nutty example, but it’s dramatically effective.) In the Empty Window project, we’ll create a button subclass, MyRedButton:

1. In the Project navigator, choose File → New → File. Specify an iOS Cocoa Touch Objective-C class. Click Next.

2. Call the new class MyRedButton. Make it a subclass of UIButton. Click Next.

3. Make sure you’re saving into the project folder, with the Empty Window group, and make sure the Empty Window app target is checked. Click Create. Xcode creates MyRedButton.h and MyRedButton.m.

4. In MyRedButton.m, in the implementation section, implement awakeFromNib:

5. - (void) awakeFromNib {

6. [super awakeFromNib];

7. self.backgroundColor = [UIColor redColor];

}

We now have a UIButton subclass that turns itself red when it’s instantiated from a nib. But we have no instance of this subclass in any nib. Let’s fix that. Edit the storyboard, select the button, and use the Identity inspector to change this button’s class to MyRedButton.

Now build and run the project. Sure enough, the button is red!

OS X PROGRAMMER ALERT

If you’re an experienced OS X programmer, you may be accustomed to rarely or never calling super from awakeFromNib; doing so used to raise an exception, in fact. In iOS, you must always call super in awakeFromNib. Another major difference is that in OS X, a nib owner’s awakeFromNib is called when the nib loads, so it’s possible for an object to be sentawakeFromNib multiple times; in iOS, awakeFromNib is sent to an object only once, namely when that object is itself instantiated from a nib.

A further possibility is to take advantage of the User Defined Runtime Attributes in the nib object’s Identity inspector. This allows to you to send a setValue:forKey: message to the object as it is instantiated from the nib. (Actually, it’s a setValue:forKeyPath: message; key paths are discussed in Chapter 12.) This can allow you to configure, in the nib editor, aspects of a nib object for which the nib editor itself provides no built-in interface. Naturally, the object needs to be prepared to respond to the given key, or your app will crash when the nib loads.

For example, one of the disadvantages of the nib editor is that it provides no way to configure layer attributes. Let’s say we’d like to use the nib editor to round the corners of our red button. In code, we would do that by setting the button’s layer.cornerRadius. The nib editor gives no access to this property. Instead, we can select the button in the nib and use the User Defined Runtime Attributes. We set the Key Path to layer.cornerRadius, the Type to Number, and the Value to whatever value we want — let’s say 10 (Figure 7-15). Now build and run; sure enough, the button’s corners are now rounded.

Rounding a button’s corners with a runtime attribute

Figure 7-15. Rounding a button’s corners with a runtime attribute

To intervene with a nib object’s initialization even earlier, if the object is a UIView (or a UIView subclass) or a UIViewController (or a UIViewController subclass), you can implement initWithCoder:. Note that initWithCoder: is not the initializer that is stubbed out for you by the template; instead, for a UIView subclass, you are given initWithFrame:. For example, our MyRedButton class has an initWithFrame: stub. However, this will do you no good if the instance comes from a nib, because initWithFrame: is not called when a UIView is instantiated by the loading of a nib — initWithCoder: is called instead. (Implementing initWithFrame:, and then wondering why your code isn’t working when the view is instantiated from a nib, is a common beginner mistake.)

A possible reason for implementing initWithCoder: would be the same reason why you’d implement any initializer — namely, to initialize additional instance variables declared by your subclass. The structure of initWithCoder: is much like the structure of any initializer (seeChapter 5): you’ll call super at the start, and return self at the end:

- (id) initWithCoder:(NSCoder *)aDecoder {

self = [super initWithCoder:aDecoder];

if (self) {

self->_myIvar = // whatever

}

return self;

}