Chapter 13. Interface Builder

WHAT'S IN THIS CHAPTER?

  • Creating nib documents

  • Adding objects to a nib document

  • Configuring and connecting objects together

  • Defining and creating custom objects

  • Customizing Interface Builder

Interface Builder is a graphical user interface editor. Interface Builder and the Xcode IDE work hand in glove to create a fluid, dynamic, and (nearly) seamless workflow for designing and implementing your user interface objects. Getting the most out of Interface Builder is essential to any Mac or iPhone development project.

Interface Builder has a long history. Interface Builder and Project Builder (later renamed Xcode) trace their lineage all the way back to NeXT, where they were originally conceived. Twenty years later, the roles of these two applications remain largely unchanged — a testament to the vision of its creators. You write your code (controller) in Xcode using text editors and compilers. You design your interface (view) in Interface Builder using graphical design tools and object inspectors.

Although this is not a book about programming, it's very difficult to describe how to use Interface Builder without understanding what Interface Builder does and the technologies that allow it to work. This is a common source of confusion for new developers, particularly those coming from other development environments. If you fall into this category (or don't know whether you fall into this category), read through the sections "What Is Interface Builder?" and "Interface Builder Workflow." Readers comfortable with Interface Builder concepts can skip ahead to the sections that describe specific features.

WHAT IS INTERFACE BUILDER?

In a nutshell, Interface Builder, shown in Figure 13-1, edits a graph of archived objects stored in a data file. That's a terse statement, but it accurately captures the key concept behind Interface Builder. Specifically, Interface Builder edits the contents of a nib document. A nib document contains archived objects — also called serialized, marshaled, or freeze-dried objects. The nib document is transformed into a nib file when the project is built. At run time, you "load" a nib file; this un-archives (de-serializes, un-marshals) the graph of objects, creating instances of objects with preset properties, indistinguishable from objects created programmatically.

Note

NIB originally stood for NeXT Interface Builder document, but Apple has officially rechristened the extension Interface Builder Document. Although modern nib documents are actually XIB (XML Interface Builder) files, the terms "nib," "nib file," and "nib document" are used genetrically to describe all Interface Builder documents, regardless of their actual format. The term "nib document" is used here when talking about the document file (or bundle) that you edit in Interface Builder, while "nib file" usually refers to the binary deployment file loaded by your application.

FIGURE 13-1

Figure 13-1. FIGURE 13-1

By editing an archived data file, Interface Builder allows you to define complex graphs of interconnected objects, customize them in a myriad of ways, and do all of that using visual design tools. At run time, the entire set of objects is instantiated, initialized, and connected together with a single code statement — or no code at all, for nib files loaded automatically by the framework. This improves your productivity and the robustness of your applications in a number of ways:

  • Your application code is less brittle because, simply, there's less code — sometimes no code at all.

  • It's easier, faster, and more rational to create an interface design using a graphical design tool rather than hard-coding values in your program. Should the coordinates of your input text field be (314,20,276,22) or (20,314,22,276)?

  • NIB files are more efficient. An archived object data stream is generally far more compact than the code required to create, initialize, configure, and connect that same set of objects.

  • Changes to your interface often don't require any code changes. This minimizes debugging and reduces the chance of introducing unexpected errors.

  • Your interface can be redefined based on the location and language of your user, or for any other reason you choose. Multiple nib files that represent the same, or similar, interfaces can be dynamically selected at run time to change the look and feel of your application. The operating system automatically loads the correct nib file for your user's language and locale. You can selectively load nib files programmatically based on any criteria you define.

Almost as important as what Interface Builder is, is what Interface Builder is not:

  • Interface Builder is not a template editor.

  • Interface Builder is not a code generator.

  • Interface Builder is not a compiler.

If you've come from a development environment where the graphical user interface design tools create scripts, layout information files, generate source, or insert binary code into your application, set those concepts aside. Interface Builder edits archived objects, or specifically data, that just happens to describe objects. Everything you do in Interface Builder will be from the perspective of objects, their properties, and their relationships — the same way you design with objects in your code. The result (the nib file) is just data. It's data during development; it's data at build time; and it's still data in your finished application. Only when the data is un-archived does it become objects in your application.

Code vs. Interface Builder

To provide an unambiguous example, consider the following two programs. The first program, shown in Listing 13-1, creates a window and populates it with some controls.

Example 13-1. Creating a Window Programmatically

- (void)makeNewRecordWindow
{
    NSRect frame = NSMakeRect(100.0,100.0,349.0,123.0);
    newRecordWindow = [[NSWindow alloc]
                        initWithContentRect:frame
                                  styleMask:(NSTitledWindowMask|
                                             NSClosableWindowMask|
                                             NSMiniaturizableWindowMask)
                                  backing:NSBackingStoreBuffered
                                      defer:YES];
    NSView* windowContentView = [newRecordWindow contentView];
    frame = NSMakeRect(253.0,12.0,82.0,32.0);
    NSButton* okButton = [[NSButton alloc] initWithFrame:frame];
    [okButton setTitle:@"Create"];
    [okButton setButtonType:NSMomentaryLightButton];
[okButton setBezelStyle:NSRoundedBezelStyle];
    [windowContentView addSubview:okButton];
    frame = NSMakeRect(171.0,12.0,82.0,32.0);
    NSButton* cancelButton = [[NSButton alloc] initWithFrame:frame];
    [cancelButton setTitle:@"Cancel"];
    [cancelButton setButtonType:NSMomentaryLightButton];
    [cancelButton setBezelStyle:NSRoundedBezelStyle];
    [windowContentView addSubview:cancelButton];
    frame = NSMakeRect(20.0,90.0,130.0,13.0);
    NSTextField* titleField = [[NSTextField alloc] initWithFrame:frame];
    [titleField setStringValue:@"Record Name:"];
    [titleField setEditable:NO];
    [titleField setSelectable:NO];
    [titleField setBordered:NO];
    [titleField setDrawsBackground:NO];
    [windowContentView addSubview:titleField];
    frame = NSMakeRect(20.0,60.0,309.0,22.0);
    NSTextField* nameField = [[NSTextField alloc] initWithFrame:frame];
    [windowContentView addSubview:nameField];

    [newRecordWindow makeKeyAndOrderFront:self];
}

The Interface Builder document that creates an identical window was shown in Figure 13-1. The code needed to create, initialize, and display the window defined by the nib document shown in Figure 13-1 is shown in Listing 13-2.

Example 13-2. Creating a Window Stored in a Nib File

- (void)makeNewRecordWindow
{
    [[NSBundle mainBundle] loadNibNamed:@"NewRecord" owner:self];
    [newRecordWindow makeKeyAndOrderFront:self];
}

The two different -makeNewRecordWindow methods, shown in Listing 13-1 and Listing 13-2, accomplish exactly the same thing. After the method returns, the objects that are created, their relationships, properties, and inter-object references are the same.

It should be obvious that the window design in Figure 13-1 is far easier to comprehend and manipulate than the code in Listing 13-1. For example, a button object could be repositioned simply by dragging it to a new location. This is vastly simpler, and more predictable, than trying to edit the coordinate constants in Listing 13-1 — assuming you could find them.

This brings me to one last, but important, benefit of using Interface Builder:

  • Your application doesn't give up any control or features by using nib created objects. You are free to programmatically manipulate objects created by a nib file just as you would objects created programmatically. You can define as much, or as little, in the nib file as appropriate. Many nib files define nothing more than a container object that's later populated programmatically.

The Three C's of Interface Builder

Interface Builder lets you do three things:

  • Create instances of objects

  • Configure object attributes

  • Connect objects together

You can create instances of any of the multitude of predefined objects provided in Interface Builder's library, or you can create instances of classes that you've defined yourself. Creating objects is described in the section "Creating Objects."

You edit the attributes (properties) of object instances in a variety of ways, but the result is ultimately the same; the property values you select become part of the archive data stream and are used to initialize the object when it's created at run time. This is covered in the sections "Selecting Objects" and "Configuring Objects."

Finally, and probably what Interface Builder is most famous for, is the ability to connect objects. A connection is just IB-speak for an object reference. In Interface Builder, you make a connection by dragging an outlet or action from one object to another. At run time, the connection sets an instance variable of the referring object to point to the object that you connected it to. It's that simple. The effect of connecting the outlet inputField to an NSTextField object would be equivalent to writing the code:

self.inputField = [NSTextField new];

You can learn the many different ways of connecting objects in the section "Connecting Objects."

That's it! That's all Interface Builder does. With the mystery of Interface Builder out of the way, I can now show you how Interface Builder integrates into Xcode and your development workflow.

INTERFACE BUILDER WORKFLOW

Interface Builder is (technically) a standalone editor. You can launch Interface Builder and use it to create, edit, and save nib documents. Except in a few rare cases — say where you might want to use Interface Builder to "hack" an existing nib document — you're most likely to use Interface Builder as an adjunct editor for an Xcode project.

Editing NIB Documents in an Xcode Workflow

The typical workflow when using Xcode and Interface Builder is shown in Figure 13-2.

FIGURE 13-2

Figure 13-2. FIGURE 13-2

Interface Builder isn't a compiler, but it does observe and interpret your project's class declarations. It understands the classes, inheritance, properties, and methods that you declare and synchronizes those with your nib document. Your development workflow might proceed like so:

  1. Xcode: Define a new view controller class.

  2. Interface Builder: Create a nib document to define the objects in the interface.

  3. Interface Builder: Add some input text field objects to the interface.

  4. Xcode: Add some instance variables to the view controller class that will refer to those input field objects.

  5. Interface Builder: Connect the input field objects to the instance variables.

  6. Xcode: Create an action method.

  7. Interface Builder: Add a button to the interface and connect its action to the controller's new method.

  8. And so on . . .

As you can see, you'll jump back and forth between Xcode and Interface Builder quite a lot while working on your interface. A number of features and shortcuts for making this workflow nearly seamless are covered at appropriate places in this chapter.

Simulating an Interface

During interface design and development, you'll often want get an approximate idea of how your interface will look and behave. Building and running your application is the obvious way to test it, but sometimes that's not convenient; projects under development are often in a state where they can't be built and tested.

Interface Builder provides an interface simulator, which you can launch using the File

Simulating an Interface

Figure 13-3 shows an iPhone interface design and the same nib document running in the iPhone simulator. Interface Builder uses the iPhone simulator for Cocoa Touch documents. Cocoa documents are presented in a Cocoa simulator built into the Interface Builder application. When you're done with the simulation, choose the Quit command.

FIGURE 13-3

Figure 13-3. FIGURE 13-3

The simulator presents your interface using the standard framework objects, sans any programmatic enhancements provided by your application. The results can be quite rich or stunningly dull. Consider a custom view object that's drawn by your application; the simulator will present a blank white square.

The simulator provides canned data for list, table, and browser views (the names of cities, in the example shown in Figure 13-3). Editable text fields are editable; date pickers are pickable; and so on. The simulator is good for checking window resizing behavior, multi-tab views, table column resizing, and the like. Most buttons and application-specific menu items will be non-functional, of course.

Some interface objects can automatically record position and other state information in the user defaults for your application. For example, the NSWindow object can record its position and size when closed and a check box button can be bound to a user defaults property. The next time the application/simulator is launched, the position of the window and the state of the button will be restored from the user defaults.

Interface Builder provides a "scratch pad" user defaults file for each simulated nib document. This transient set of preferences can be set to be periodically, or manually, erased from the Simulator tab of the Interface Builder preferences. Erasing the preferences clears all user default values, as though the application was being run for the first time.

Building Your Project from Interface Builder

If you look at the workflow diagram in Figure 13-2, you'll see that it's very typical to write code, make connections in Interface Builder, switch back to Xcode, and then build and test your application.

Interface Builder provides a shortcut: the File

Building Your Project from Interface Builder

INTERFACE BUILDER'S INTERFACE

This section starts with a brief tour of Interface Builder's interface. One reason it will be brief, and also one of the reasons Interface Builder is so easy to use, is that there are basically only three interface elements: the nib document window, the inspector palette, and the library palette. All three are shown in Figure 13-4 and Figure 13-5.

FIGURE 13-4

Figure 13-4. FIGURE 13-4

FIGURE 13-5

Figure 13-5. FIGURE 13-5

Figure 13-4 shows a Cocoa nib document, and Figure 13-5 shows a Cocoa Touch (iPhone/iPod) nib document. When you open a nib document, the contents of the file are represented abstractly in the nib document window, as shown in the lower left of Figures 13-4 and 13-5. Nib documents contain objects, and those objects are shown here either as icons, hierarchically, or in a browser. You select which view you want to see in the toolbar. Figure 13-6 shows the contents of a nib document in all three views. The icon view only shows the top-level objects. You will also find a few special objects listed; these are described later in the section "Placeholder Objects."

FIGURE 13-6

Figure 13-6. FIGURE 13-6

The two important palettes are the inspector palette and the library palette, both described next. Most of the other windows you'll be working with will be view windows. View windows present your view objects (approximately) as they will appear in your application: a window is shown as a window, a menu as a menu, a button as a button. You can edit your objects in either the nib document or manipulate their visual representation in a view window. The effect is the same.

Inspector Palette

Shown in the middle of Figures 13-4 and 13-5 is the inspector palette. The inspector palette shows the properties and settings of the currently selected object (or objects). It's where you customize and connect objects. These activities are described in the sections "Configuring Objects" and "Connecting Objects." Much of your time will be spent using the inspector palette to fine-tune your objects.

Several different inspectors all occupy the same palette window; changing inspectors just changes the view of the single inspector palette window. You can change inspectors using the tabs at the top of the inspector window or using the menu commands in the Tool menu.

You'll notice that there are different sets of inspectors for the Cocoa and iPhone nib documents. Only inspectors appropriate to the nib document architecture appear in the palette. For instance, the iPhone OS (as of this writing) does not support bindings, so there is no bindings inspector when working with a Cocoa Touch (iPhone) nib document.

Library Palette

On the right in Figures 13-4 and 13-5 is the library palette. The library palette is your source for new objects and other resources. Creating a new object is described in the section "Creating Objects." The library is organized into groups, selectable using the tab control at the top of the palette window. To create a window, for example, just drag a window object out of the library palette and drop it anywhere in the screen. To add a button to that window, drag a button object off the palette and drop it into the window.

The library palette's Classes view lists all of the classes that Interface Builder knows about. While many of these classes are represented in the Objects view, the Classes view also includes all custom classes you've defined and is organized by name rather than by function. Either view can be used as a source of new objects.

Note

In addition to missing inspector palettes, the active nib document architecture may cause other Interface Builder interface elements to appear or disappear. Carbon nib documents, for example, do not support creating objects with arbitrary types (classes), so there will be no Classes tab in the Library palette when a Carbon document is active.

The Media tab represents content files (mostly images) to which objects can refer in your nib document. These include system resources, like standard button icons and sounds, as well as any resources you've added to your project.

The library palette presents each list in one or more panes. In the objects list, the top portion lets you browse and select categories of objects. The individual objects in the selected categories are displayed in the middle pane. The bottom pane presents interesting information about the selected objects. The layout of the list can be controlled with the pop-up menu at the bottom of the palette. The other lists have similar features and controls.

If you know the name, or part of the name, of the class or media object you're looking for, type it into the search field at the bottom of the window, as shown in Figure 13-7.

FIGURE 13-7

Figure 13-7. FIGURE 13-7

Multiple NIB Document Windows

Like Xcode projects, Interface Builder always has one active nib document. Also like Xcode, the Window

Multiple NIB Document Windows

To aid you in identifying the view windows contained in that nib document, Interface Builder dims any view objects that are not part of the active nib document. Figure 13-8 shows two nib documents: one containing a Cocoa window and menu and the other containing a Cocoa Touch view. The Cocoa document is active. This dims all of the windows belonging to the other nib document.

FIGURE 13-8

Figure 13-8. FIGURE 13-8

CREATING A NIB DOCUMENT

Interface Builder edits nib documents, so the first thing you must do is create a nib document. If you created your project in Xcode using one of the standard templates, you probably already have a nib document in your project. Open the nib document in the source group and Xcode launches Interface Builder. Also, many new file templates in Xcode also create companion nib documents. For example, creating a new iPhone view controller class in Xcode also adds its associated nib document to the project for you.

If you already have a nib document, or created a new one using Xcode, you can skip this section. Come back when you need to create one.

Choosing a Template

If you need to create additional nib documents, launch or switch to Interface Builder and choose the File

Choosing a Template
FIGURE 13-9

Figure 13-9. FIGURE 13-9

Choose a template from the list. The templates are organized into groups, depending on the SDKs you have installed. This can include Cocoa, Cocoa Touch (iPhone/iPod), Carbon, and IB Kit (Interface Builder Kit) groups. All of the templates in the Cocoa group create a Cocoa nib document; Carbon group templates create Carbon nib documents, and so on. You cannot change or convert between document types, so make sure you choose a template from the correct group. The following tables provide a brief summary of the templates.

COCOA TEMPLATES

CONTENTS

Application

Makes a Cocoa nib document containing a standard Cocoa application menu bar and an empty window. This template is appropriate for a "single window" (non-document based) application. However, you should rarely need this template — all Xcode project templates for Cocoa applications already include a nib document containing the same thing.

Empty

Creates an empty Cocoa nib document.

Main Menu

Contains a standard application menu bar. Again, you're unlikely to use this template unless you're creating alternate menu sets for your application.

View

Contains a single NSView object. Useful for defining a subview. You can populate it to include any combination of standard and custom view objects (you can change the class of the view object to one of your own).

Window

Creates a Cocoa nib document containing a single, empty, NSWindow object.

COCOA TOUCH TEMPLATES

CONTENTS

Application

Creates a Cocoa Touch nib document containing a UIWindow and an application delegate object. Again, you should rarely need this template — the Xcode project templates for an iPhone application will already include a nib document containing a much more specific set of objects appropriate to the type of application you're creating.

Empty

Creates an empty Cocoa Touch nib document.

View

Contains a single UIView object. Useful for defining a complete view, subview, or a reusable cell (in the iPhone framework, a cell is a subclass of UIView). You can expand it to include any combination of standard and custom view objects.

Window

Creates a Cocoa Touch nib document containing a single, empty, UIWindow object.

CARBON TEMPLATES

CONTENTS

Application

Creates a Carbon nib document containing a Carbon application menu bar and an empty window. This template is appropriate for a "single window" (non-document based) application.

Dialog

A single Movable Modal window.

Empty

An empty Carbon nib document.

Main Menu

Contains a standard application menu bar. Again, you're unlikely to use this template unless you're creating alternate menu sets for your application.

Window

A single Carbon window.

Note

Interface Builder still supports legacy Carbon nib documents, but support for Carbon (pure C) programming and technologies is being systematically removed from both the operating system and the Xcode development tools in favor of the more modern Cocoa technologies. This chapter focuses almost exclusively on development in a Cocoa environment. For more information about Carbon nib documents, refer to the Carbon Resources Programming Guide at http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/LoadingResources/CarbonNibs/.

IB KIT TEMPLATES

CONTENTS

inspector

Creates a Cocoa nib document containing an inspector palette subview. Use this template to create your own extensions to Interface Builder. See the "Customizing Interface Builder" section for more details.

Library

Creates a Cocoa nib document containing the NSView objects used to present a custom Interface Builder object in the library palette.

When you have selected your desired template, click the New button. Alternatively, you can avoid creating a new file and open an existing document by clicking the Open an Existing Document button. This option is here mostly because Interface Builder presents the new document assistant whenever you start Interface Builder without opening a document, or when you close all of the document windows, thus providing a quick method to either create a new nib document or open an existing one.

Adding a New Nib Document to a Project

When you save a newly created nib document for the first time, Interface Builder looks to see whether it is saved inside the project folder of any project currently open in Xcode. If it is, Interface Builder offers to add it to that project through the dialog shown in Figure 13-10.

FIGURE 13-10

Figure 13-10. FIGURE 13-10

Select the targets you want the nib document to be included in and click the Add button.

If you plan to localize your nib document, follow these steps:

  1. Create the new nib document for the development (that is, your) localization.

  2. Save the file in the project folder and let Interface Builder add it to the project.

  3. Close the nib document in Interface Builder.

  4. Localize the nib document in Xcode as described in the "Localizing Files" section of Chapter 6.

OPENING SISTER LOCALIZATIONS

In addition to the obvious ways of opening a nib document — opening it from Xcode or the Finder, the File

OPENING SISTER LOCALIZATIONS

The File

OPENING SISTER LOCALIZATIONS

CREATING OBJECTS

The first "C" of Interface Builder is creating objects. Objects are easy to create: drag an object from the library palette into your nib document or view window.

Creating an object is as easy as dragging an instance out of the library item and dropping it into your nib document window, as shown in the middle in Figure 13-11. You can also drop a view object directly into a view window, as shown on the left in Figure 13-11 — as long as it's an object appropriate for that view.

FIGURE 13-11

Figure 13-11. FIGURE 13-11

Using either technique, subview objects can be inserted directly into the view hierarchy. When dropping into the nib document window, drop the object inside the appropriate view. When dropping a new object in a view window, it's implied that the new object will be inserted into a container view, even if that container is just the window object. Interface Builder highlights and identifies the container that will receive the new object. Figure 13-12 illustrates how the location of the drop determines which superview will receive the new object.

FIGURE 13-12

Figure 13-12. FIGURE 13-12

In all cases, containers only accept certain object classes (or their subclasses). For example, you cannot add an arbitrary object (such as NSObject) inside a view container, no matter where you attempt to drop it.

The library palette will only create objects in its repertoire. See the section "Custom Classes" later in this chapter to learn how to create objects with custom classes.

Here are a few shortcuts and tricks for creating objects in Interface Builder:

  • Create a new window by dragging a window object out of the library palette and dropping it anywhere on the screen.

  • To create an unattached view (NSView, UIView, and so on) object, drag a new view object into the nib document window to create a top-level object. Double-click the new object to open it in a view window where you can edit its content.

  • You cannot create a top-level Cocoa application menu bar object using the NSMenu object in the library palette. (It will create a menu bar, but it won't be the application menu bar.) Should you ever need to create one, use the Cocoa Main Menu template to create a new nib document that contains a full application menu bar object, copy it into your nib document, and then edit it as desired.

COPYING, DUPLICATING, AND DELETING OBJECTS

Another way of creating an object that should not be overlooked is to duplicate an existing object. This can save a lot of time when creating groups of similarly configured objects. The following actions create copies or delete objects in your nib document:

  • Edit

    COPYING, DUPLICATING, AND DELETING OBJECTS
  • Edit

    COPYING, DUPLICATING, AND DELETING OBJECTS
  • Edit

    COPYING, DUPLICATING, AND DELETING OBJECTS
  • Edit

    COPYING, DUPLICATING, AND DELETING OBJECTS
  • Delete key

  • Edit

    COPYING, DUPLICATING, AND DELETING OBJECTS
  • Option+drag

  • Drag an object from one nib document to another

Holding down the Option key while dragging objects, or selecting the Edit

COPYING, DUPLICATING, AND DELETING OBJECTS

If you repeatedly use complex objects or layouts in your projects, you can save preconfigured objects in the library palette. See the section "Saving Custom Objects" toward the end of this chapter.

SELECTING OBJECTS

Before you can examine or change the attributes of an object, you must select it. This sounds simple — and it usually is — but there is some subtlety to selecting objects in Interface Builder of which you'll want to be aware.

There are two places to select Interface Builder objects. All objects appear in the nib document window and can be selected there. View objects can optionally appear in a view window, approximately as they will appear in your application. Selecting a view object is equivalent to selecting the same object in the nib document window.

Objects in the Nib Document Window

Selecting objects in the nib document window is simple and straightforward: select the object or objects with which you want to work using any of the three view modes. The icon view only allows you to select top-level objects, and the browser mode only lets you select multiple objects within the same branch of the hierarchy. I tend to use the list view most of the time. All of the standard Mac OS X icon/list selection gestures work here: Click, Shift+click, Command+click, and dragging out a rectangle.

Note

Selecting a container object does not select any of the objects that it contains. If you want to edit the attributes of a view and all of its subviews simultaneously, you must explicitly select both the container view and its subview objects.

The advantage of selecting objects in the nib document window is that they are unambiguous. The nib document window lists each and every object defined in that document. Of course, the nib document window is the only place you can select objects that don't have a visual representation.

The disadvantage is that it may sometimes be difficult to distinguish between different objects in the list. For example, a nib document that defines five untitled radio-button objects simply shows five identical radio-button icons, whereas in a view window, each radio button object appears as a radio button, at the position it will be in that window. See the "Identity" section to learn how to name objects so they are easier to find in the nib document window.

Object Order

The order in which subobjects appear in the nib document window list defines their order in the nib document. Often the order of objects is completely immaterial. Within a view container, the order defines the Z-order of the subviews — the order in which the objects overlap. The first object in the list will be behind all of the objects that come after it. You can reorder objects in the document window by dragging them to a new position in the list, or you can use any of these commands on view objects:

  • Layout

    Object Order
  • Layout

    Object Order
  • Layout

    Object Order
  • Layout

    Object Order

Object order is different from object position (see the "Moving and Resizing Objects" section).

View Objects

View objects in the nib document window may also appear as "themselves" — an approximate representation of that class of view object at run time — in a separate view window. For example, a view window containing the menu of your application lets you see, select, and edit the contents of your menus, more or less as the menu items will appear in your application. A single NSView or UIView object will appear in a window where you can resize it, add subviews, and customize its appearance. If the view object is, itself, a window object, the view window represents that window object in the nib document.

View objects do not have to appear in a view window. Any view window can be closed, tidying up your workspace. To reveal it again, double-click the view object in the nib document window. The view object, or the view window that contains it, will open again. This will also select the view object in the view window. Unless the view window is representative of an actual window object in the nib document, the view window is just a convenient container provided by Interface Builder. For example, the position of the view window that contains a menubar object is superfluous.

Selecting Multiple View Objects

Select a single view object by clicking it. You can select multiple view objects by dragging out a selection rectangle. Any view objects whose position intersects the selection rectangle will be selected, as shown in Figure 13-13.

FIGURE 13-13

Figure 13-13. FIGURE 13-13

When single-clicking an object, the selection can be modified using one of the following keyboard modifiers:

  • Holding down the Shift key adds the object to the set of currently selected objects.

  • Holding down the Command key toggles the selection of the object: an unselected object is selected (same as Shift), and a selected object is unselected.

Selecting Interior View Objects

Some objects, like tab and split pane views, are containers for other view objects. To select a container object, click any unoccupied region within the container. To select an object within the container, click directly over that object. Figure 13-14 shows two different selections: on the left, the button object contained in the box object is selected; on the right, the box object itself is selected.

FIGURE 13-14

Figure 13-14. FIGURE 13-14

Sometimes, selecting a container is inconvenient or impossible (a split view with an invisible divider might not have any unoccupied region on which to click). Normally when you click a view object, Interface Builder selects the most specific object in the visual hierarchy at the clicked coordinate. This is the so-called "inside out" selection strategy.

Holding down the Command key while clicking reverses this logic. Interface Builder selects the outermost container that occupies the clicked coordinate. In the example shown in Figure 13-14, clicking the Can Get Smarter radio button selects that NSButton object. Holding down the Command key while clicking same button selects its enclosing NSBox object.

Drilling Into View Objects

Tables and many other kinds of nested views support a selection technique called drilling. The first time you click the object, you select the container object. Single-click again, and the selection "drills down" into the object hierarchy.

Using the table view object in Figure 13-15 as an example, imagine positioning your cursor over the middle Text Cell object. Clicking four times slowly — remember these are all single-click actions — produces the following selections:

  1. The first click selects the scroll view object.

  2. The second click selects the table view object nested inside the scroll view.

  3. The third click selects the second table column object of the table view.

  4. The fourth click selects the text cell object used to draw the cells of the second column.

FIGURE 13-15

Figure 13-15. FIGURE 13-15

The same technique works with the column header objects of the table. Most view objects that form a similar hierarchy can be drilled into, such as any scroll view. Of particular note is the cell object nested inside each control view object. It's not always obvious, but every control view (button, slider, and so on) is actually two objects: a controller object and a cell object that provides its look and feel.

Object Selection vs. Object Focus

There's a subtle difference between selecting a view object and having a view object that's the current focus of Interface Builder. Click once to select a container object. Click again to make it the focus. Figure 13-16 shows the difference. On the left, the Box view object is selected. On the right, the box view has the current focus.

FIGURE 13-16

Figure 13-16. FIGURE 13-16

For many commands, there's no difference between these two states, but for some, notably Edit

FIGURE 13-16

Adjusting the Selection

A number of commands change the selection. When selecting and unselecting multiple objects, don't neglect these perennial favorites:

  • Edit

    Adjusting the Selection
  • Edit

    Adjusting the Selection

The following four commands let you shift the selection to a different object relative to the currently selected object, or objects:

  • Tools

    Adjusting the Selection
  • Tools

    Adjusting the Selection
  • Tools

    Adjusting the Selection
  • Tools

    Adjusting the Selection

The Tools

Adjusting the Selection

The Next and Previous Sibling commands shift the selection to the next, or previous, object in the same container object. These commands navigate by object order (Z-order), not position.

CONFIGURING OBJECTS

Objects in Interface Builder wouldn't be much use if you couldn't bend and shape them to your needs. Most of your time in Interface Builder will be spent editing objects, and you have many different ways to do that. The overt aspects (visible text, placement, and size) of view objects can be manipulated directly: drag an object around to reposition it; double-click the text of an object to change it.

Less obvious attributes, such as formatting options and bindings, are manipulated in the inspector palette. A few specialized commands also exist for aligning objects and grouping objects in containers.

Moving and Resizing Objects

An object, or a group of selected objects, can be repositioned in a view window simply by dragging it to another location, as shown in Figure 13-17. Depending on the layout, some objects may not be repositioned. For instance, an object in one half of a split view always occupies that entire space. It cannot be repositioned, because its location and size are determined by the split view. Altering the position of the split view or its divider is the only way to change that object's position in the window.

FIGURE 13-17

Figure 13-17. FIGURE 13-17

Interface Builder displays guidelines as an object is dragged. When the object is released, it "snaps" to nearest guideline. See the "Guides" section to find out how to control these automatic guidelines or create your own.

The arrow keys nudge the selected objects one pixel in any direction. Hold down the Shift key to nudge them 10 pixels at a time.

Dragging the handles on the edge of an object resizes it. Some objects cannot be resized, or can only be resized in certain directions. For example, the height of a button is fixed in Cocoa. You can only change its width. Using the resize handles, you can only resize one object at a time.

Sizing Objects to Fit

Choose Layout

Sizing Objects to Fit

Clipped objects are objects that are too small to display their content, and appear with a grey + symbol, indicating that there's more to the view than will be visible, as shown in Figure 13-18. The usual culprits are buttons and pop-up menu objects that are too narrow to display their title or selection.

FIGURE 13-18

Figure 13-18. FIGURE 13-18

The two commands Tools

FIGURE 13-18

Making Objects the Same Size

Use the Layout

Making Objects the Same Size

Aligning Objects

In addition to the automatic guides that appear when you drag or resize an object, the alignment commands provide a number of methods for aligning objects in a view. All of the alignment commands are found in the Layout

Aligning Objects
  • Layout

    Aligning Objects
  • Layout

    Aligning Objects
  • Layout

    Aligning Objects
  • Layout

    Aligning Objects
  • Layout

    Aligning Objects
  • Layout

    Aligning Objects
  • Layout

    Aligning Objects
  • Layout

    Aligning Objects
  • Layout

    Aligning Objects

The first seven commands all reposition two or more selected objects so that the desired edge or center of every object is at the same coordinate.

The last two commands can be applied to a single object or a group of objects contained within another view. These commands position the object, or objects, so that it is centered in its superview. When used with a group of objects, the group is treated as a whole; the relative position of the objects in the group remains the same and all objects are moved equally so the group is centered in the superview.

View Bounds Indicators

The two aids for visualizing the actual location of view objects in an interface are as follows:

  • Layout

    View Bounds Indicators
  • Layout

    View Bounds Indicators

These two commands draw a thin blue (bounds) or red (layout) line to indicate the exact coordinates occupied by the objects in a view, as shown in Figure 13-19. The layout rectangle will also include a line showing where the text baseline of the object lies, for those objects that display text.

FIGURE 13-19

Figure 13-19. FIGURE 13-19

The distinction between the layout and bounds rectangles is primarily of interest to Cocoa developers. The bounds of a Cocoa Touch view is invariably the same as its layout rectangle, so turning on the layout rectangle indicator is sufficient.

Relative Position Indicators

Holding down the Option key while one or more objects are selected reveals the spatial relationship between objects. With the Option key held down, let the mouse pointer hover over some other object, the unoccupied area in a container, or the window itself. Interface Builder illustrates the relationship between the two. In Figure 13-20, the check box button is selected and the cursor is hovering over the push button while the Option key is held down.

FIGURE 13-20

Figure 13-20. FIGURE 13-20

Subviews

A number of view objects types are containers for other view objects. The container is the superview and the view objects it contains are its subviews. Every view has its own size and position within its superview and can itself contain any number of subviews. This nesting of objects is reflected in both the nib document window and in how the objects are displayed at run time.

You have two ways of moving an object into, or out of, a container view:

  • In the nib document window, drag the object out of one container into another.

  • Use one of the Embed commands.

The embed commands are found in the Layout

Subviews
  • Layout

    Subviews
  • Layout

    Subviews
  • Layout

    Subviews
  • Layout

    Subviews
  • Layout

    Subviews
  • Layout

    Subviews
  • Layout

    Subviews

Each command creates a new container view object in the same superview as the selected objects, and then moves those objects from their current container into the newly created subview. Figure 13-21 shows the effect of selecting four radio buttons and using the Layout

Subviews
FIGURE 13-21

Figure 13-21. FIGURE 13-21

All of these commands are essentially a shortcut for these steps:

  1. Use the library palette to create a new container view.

  2. Select the sibling views you want the new view to contain.

  3. Drag the sibling views into the container view (Edit

    FIGURE 13-21

The inverse of all of these commands is the single Layout

FIGURE 13-21

Guides

Laying out a window or dialog box so that it is functional and aesthetically pleasing is no small feat. To help you space and align items in your layout, Interface Builder provides two kinds of guides. A guide is a vertical or horizontal line at some coordinate that aids you in aligning objects.

Whenever you position an object by dragging, the boundary of the object "snaps" to that coordinate whenever it is near a guide.

Aqua guides are relative to the edges of other objects, which include containers, in the layout. These distances are based on the Aqua interface design standard. For example, the suggested distance between a button and the edge of a window is 20 pixels. Dragging the button, or resizing the window as shown in Figure 13-22, automatically places Aqua guides 20 pixels from the edges of the window and nearby objects.

FIGURE 13-22

Figure 13-22. FIGURE 13-22

Aqua guides are very intelligent, but they don't know everything. You should still refer to the Human Interface Guidelines in making layout decisions. For example, the Human Interface Guidelines suggest that buttons that destroy data should be farther away from buttons that save data or cancel an operation. Interface Builder has no way of knowing what the buttons in your layout do, and are therefore limited in what suggestions they can offer.

Note

Apple's Human Interface Guidelines are so important that Interface Builder has a built-in shortcut to them. Choosing the Help

FIGURE 13-22

User guides are the other kind of guides. User guides are fixed guides that you can position anywhere in a layout. Objects dragged near a user guide snap to it just as they would snap to an Aqua guide. The Layout

FIGURE 13-22
FIGURE 13-23

Figure 13-23. FIGURE 13-23

You can disable guide snapping temporarily or permanently:

  • Hold down the Command key while dragging an object to temporarily disable guide snapping.

  • Choose Layout

    FIGURE 13-23

To delete a user guide, drag it outside the window bounds.

Inspector Palette

The inspector palette is where the nitty-gritty details of your objects are manipulated. The inspector palette (see Figure 13-1) is a floating window that constantly shows the attributes for the currently selected object or objects. The palette is organized into different panels, selectable using the tabs at the top of the palette or any of the "Inspector" commands in the Tools menu. Each inspector configures some aspect of the object. The possible inspector panels are:

INSPECTOR

USE

Attributes

Edits the class-specific properties.

Effects

Sets Core Animation effects for a Cocoa object.

Size

Establishes the size, position, orientation, resizing behavior, minimum/maximum size, and other visual layout attributes.

Bindings

Binds selected properties of a view object to properties of other objects.

Connections

Creates and inspects the connections between the object and other objects.

Identity

Defines the class, name, and identity of the object.

Which inspectors appear depends on the type of nib document you are editing. A Cocoa document presents all of these inspectors, whereas a Cocoa Touch document shows only the Attributes, Size, Connections, and Identity panels.

In the case of the bindings panel, the difference is significant. Cocoa Touch does not support bindings, so there's no binding panel at all. On the other hand, the effects panel is also missing; but that's because in the Cocoa framework Core Animation layers are an optional element of NSView objects. In Cocoa Touch, all view objects are animation layers, so many of the attributes you'd set in the effects inspector in Cocoa are set in the Attributes inspector in Cocoa Touch.

You'll find yourself switching between the various inspector panels often. I suggest learning to use the keyboard shortcuts Command+1 through Command+6. The numbers correspond to the tab positions at the top of the inspector palette window, so in Cocoa the connections inspector is Command+5, whereas in Cocoa Touch the same inspector is Command+3.

The following sections briefly describe the various inspector panels, however a complete description requires an understanding of the framework classes and their behaviors, which is far beyond the scope of this book.

Attributes

This panel is common to all nib document types and edits the class-specific attributes of an object. The attributes that are available, and what those attributes mean, vary wildly from one object to another. Figured 10-24 shows the attributes panel for three different objects.

FIGURE 13-24

Figure 13-24. FIGURE 13-24

The best place to look for descriptions of object attributes is in the API documentation for that class or structure. The title bar of the inspector changes to indicate the kind of object being inspected. In the left two inspectors in Figure 13-24, the documentation for the image view (UIImage) and menu item (NSMenuItem) classes explain every detail of the attributes for those objects. If you're unsure about the specific class of an object, see the "Identity" inspector section.

The attributes in the inspector panel are organized into groups based on the object's class inheritance. For example, a UIButton object inherits from UIControl, which inherits from UIView, UIResponder, and NSObject. When editing a UIButton, the inspector shows three groups of attributes: Button, Control, and View. Each group contains the attributes defined by the respective class (UIButton, UIControl, UIView). The UIResponder and NSObjects don't define any Interface Builder editable properties, so there is no group for those classes.

The organization of groups makes it clear to which domain each attribute belongs. You can collapse one or more groups of attributes to save screen real estate, or if perhaps you're just not interested in them.

Note

A few non-object attributes have begun to sneak into Interface Builder's inspector panel of late. Specifically, the attributes for Cocoa Touch (iPhone) views include a new "Simulated User Interface Elements" group. These are not attributes of a UIView object; they are used solely to present the view in a simulation of its superview environment at run time. Interface Builder remembers these attributes, but they aren't properties of any object at run time.

The pane on the right in Figure 13-24 is for a Carbon Button object. Carbon objects are more obtuse because the Carbon interface is C, not Objective-C, so each object type doesn't have a simple one-to-one relationship with a class. The best place to start is the User Experience documentation collection in the Carbon group of the Reference Library. The HIView Programming Guide should give you an overview of the Carbon view model. The "Handling Carbon Windows and Controls" document explains how control events are handled in Carbon applications. In brief, the C interface that lets you control something about a window structure (like passing the kWindowIgnoreClicksAttribute constant to CreateNewWindow) corresponds to an attribute in the panel (the Ignore Clicks option).

Connections

The connections inspectors let you review, establish, and destroy connections between objects, as shown in Figure 13-25. Connections are the third "C" of Interface Builder, and are described in detail in the "Connecting Objects" section, a little later in this chapter.

FIGURE 13-25

Figure 13-25. FIGURE 13-25

Briefly, the connections inspector shows the connection outlets defined for the object, and to what each of those is connected (if anything). If you click a connected connection, Interface Builder highlights the object to which it's connected.

Size

The size inspector lets you set the position, size, and related attributes for most view objects. All view objects have a rectangular region defined by its location in its superview and its size. The controls in the size inspector, as shown in Figure 13-26, allow you edit any of those values numerically. Setting an object's position numerically is sometimes easier that attempting to position or resize the object using the mouse, but has the same effect. The dimensions of some view objects are fixed, in which case those values will not be editable.

FIGURE 13-26

Figure 13-26. FIGURE 13-26

Two common controls let you define the position and size of the object in various ways. The little square graph to the left of the size and position fields lets you choose the origin to use, and the pop-up menu above lets you specify either the layout bounds or the frame bounds of the object. These alternative coordinate schemes are just conveniences provided by Interface Builder; however you enter the coordinates, they will be translated into frame bounds in the superview's coordinate system. That's what gets used to initialize the object at run time.

Note

Some objects, such as labels, have a size attribute that determines the size of its text, whereas other objects set their text size in the attributes inspector. If you can't find a size-related property in the attributes inspector, check the size inspector, and vice versa.

Resizing a container view — any view that contains other view objects — using the Size inspector also resizes its subviews according to their resize behavior, which is explained next. To resize a container view without resizing its subviews, resize the view using your mouse as described in the "Moving and Resizing Objects" section.

Many view objects have a resize behavior. You'll need to consult the documentation for the class of objects you're editing, but in general the edges of an object can be optionally fixed ("anchored") relative to the corresponding edge of its superview, and its vertical and horizontal dimension can be either fixed or variable ("springy").

Interface Builder thoughtfully provides a resize preview animation. The animation is active whenever your cursor is over the inspector palette window. It shows a simulation of the effects of resizing the object's superview. This lets you quickly visualize how your settings will affect how your object is resized. Note that this is only accurate when using Cocoa or Carbon's built-in resizing behavior, which could be overridden in your code.

The remaining attributes (window type, initial position, background color, minimum/maximum size, and so on) will be specific to the type of object you're editing.

Effects

The effects inspector lets you assign predefined filters and animation effects to Cocoa view objects. Many of these same effects (like transparency) are available for Cocoa Touch objects too; but in Cocoa Touch, all view objects are inherently drawn using Core Animation layers, so many of these capabilities are permanent features of the Cocoa Touch view object and can be found in the attributes inspector.

In Cocoa, using a Core Animation layer to render a view object is optional and must be enabled separately. You do that in the effects inspector, as shown in Figure 13-27.

FIGURE 13-27

Figure 13-27. FIGURE 13-27

Enabling Core Animation effects is simple:

  1. Select the view, or views, that should use a CALayer to perform rendering. Checking the box next to an object sends it a -setWantsLayer:YES message when the object is created. This creates a CALayer object and attaches it to the NSView object.

  2. The remainder of the inspector allows you to set common properties of the CALayer (transparency, drop shadow), attach system-supplied image filters (sharpen, blur, color adjustment), and assign default transitions for its subviews (page curl, ripple, swipe).

Bindings

Bindings are actually a third kind of connection (see the "Connecting Objects" section later in this chapter). Unlike traditional connections, bindings are set symbolically. This is for practical reasons; bindings can be very complex and don't lend themselves to the point-to-point specificity of regular Interface Builder connections.

A lot of programming in the Model-View-Controller paradigm is rote: create a property, write a getter method, write a setter method, have the setter method notify its view object when it changes, write an action method to let the view object change the property, wash, rinse, repeat. Bindings attempt to alleviate much of that tedium (and bugs) by providing standard tools to connect model objects with their visual representations. These concepts are described in the documentation for Cocoa Bindings at http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CocoaBindings/.

Note

As of this writing, the Cocoa Touch (iPhone) framework does not support bindings — sadly. There will be no bindings panel when editing a Cocoa Touch or Carbon nib document.

The Bindings panel, shown in Figure 13-28, contains the properties of an object that can be bound to a controller, data model, or any object with an observable property (technically, the property must be Key Value Observing-compliant). You bind properties of view objects to properties of other controller objects in the nib document. See the sections "Custom Classes" and "Placeholder Objects" about connecting nib document objects to your custom controller classes.

FIGURE 13-28

Figure 13-28. FIGURE 13-28

What makes bindings so brilliant is that creating the binding is often all you have to do. If your object's property is KVO-compliant (and most should be), you simply create a binding and you're finished. The binding framework takes care of all of the necessary Model-View-Controller communications needed to update your property whenever the view is changed, and automatically update the view whenever the property is changed (programmatically or otherwise). If you do have to write supporting code, it's usually just to make your property KVO-compliant.

Note

In this context, the terms attribute and property are equivalent. Interface Builder uses the term "attribute," whereas Objective-C and Key Value Coding use the term "property," but the two are interchangeable here.

Creating a binding might seem daunting at first, but it is a fairly straightforward procedure:

  1. Start by choosing the attribute you want to bind. This is often the value attribute of the view, that is, the information the view displays (a setting, a number, a string, an image, and so on). You can also bind many other attributes of a view object to a property. For example, binding the enabled attribute of a button or pop-up menu enables or disables that control simply by setting a Boolean property in your controller object. Bindings can control the current selection, the title, the color, or even the font attributes of a view object.

  2. Expand the binding group to expose its settings, enable the binding by checking the Bind To check box, and then select the controller object you want to bind to. The pop-up list will include all bindable objects in your document. You cannot create a binding to an arbitrary object in your application, unless that object happens to be the File's Owner object. See the section "Placeholder Objects" for more about the File's Owner object.

  3. If the object you selected in step 2 is a subclass of NSController, choose the Controller Key to bind to. This is essentially the first element in the Model Key Path (see step 4), but it's convenient because Interface Builder knows the list of standard bindable properties of the various NSController subclasses; you just select one from the pop-up menu. If you need to bind to a non-standard property, enter that property's name instead.

  4. Enter the path of the property to bind to in the Model Key Path field. The path is a Key Value Coding path that's relative to either the object selected in step 2 or (in the case of an NSController) the object specified by the value of the controller key in step 3. Leave the field blank if the controller key (step 3) is the value you want to bind to. Either way, it's a fully functional KVC path. It's normally a simple property name, but it can contain complex paths (for example, "mother.birthday.reminderDate") and KVC operators (such as "notifications.@count"). To bind to the value of the object itself, use the path "self."

  5. The remaining settings are all optional. You can provide a transformer object that will translate between the two objects, along with many choices for how the binding is configured, and what placeholder values are used.

You can learn more about bindings by reading the Introduction to Cocoa Bindings at http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CocoaBindings/.

Identity

The identity inspector edits the identity of the object: what it is and how it appears in the nib document window. It also edits some miscellaneous properties that, in earlier versions of Interface Builder, were in separate inspector panels.

The two most important things you can change in the identity inspector are the class of the object and how it identifies itself in Interface Builder.

Changing the class of an object is how you create instances of custom classes. This is explained in detail in the "Custom Classes" section, but in a nutshell you begin by creating a generic object that's a superclass of your custom class, and then use the identity inspector to change the class of the object to yours. In Figure 13-29, a UIImageView object was added to the nib document. In the Xcode project, a subclass of UIImageView called ZombiePortraitView was created. Interface Builder will now allow you to change the class of the object to from UIImageView to ZombiePortraitView. At run time, an instance of ZombiePortraitView is constructed, initialized, and inserted into the view.

FIGURE 13-29

Figure 13-29. FIGURE 13-29

The other really useful feature of the identity inspector is the ability to assign custom descriptions and labels to objects in your document. In Figure 13-29, the UIImageView is given a custom name and a color label, which makes it much easier to identify in the document window. The Object ID is assigned by Interface Builder and cannot be changed.

The Lock control lets you disable editing of certain properties in the attributes, size, and other inspectors. You can lock all attributes, localizable attributes, or non-localizable attributes. This is particularly handy when you're performing localizations. Localizing a nib document often entails duplicating one locale and then editing the localizable attributes. Locking non-localizable attributes keeps you from accidentally changing any attributes that shouldn't be altered. Also see the "Document Locking" section later in this chapter.

Note

If you try to make a change to an object, and you just get a big floating padlock symbol instead, it's because you've locked some aspect of your object that is preventing that action.

The identity inspector has also become a dumping ground for obscure attributes that don't fit neatly into any of the other inspectors. Depending on the nib document architecture and object type, you might find an accessibility attributes group, a tool tips group, a help system identity group, or a dynamically defined object attributes group in the inspector. If you're trying to find an attribute that you think should be editable in Interface Builder, but can't find it, poke around in the identity inspector; it might be there.

Inspecting Multiple Objects

Generally, the inspector palette displays whatever attributes are common to all of the objects in a multi-object selection. Thus, if all of the selected objects are button objects, the attributes inspector presents all of the attributes for a button object. Changing any of the attributes in the inspector updates that value in every button.

If the selection is heterogeneous, the inspector presents the most detail common to all of the objects. Selecting a button and a box view object allows you to edit the properties common to both: whether the views are hidden, their position, resize behavior, and so on, but it would not, for example, allow you to set whether the objects were enabled, because the enabled property is an NSControl attribute and NSBox is not a subclass of NSControl.

CONNECTING OBJECTS

Connections are probably Interface Builder's defining feature. To restate, a connection is little more than an object reference: one object has an instance variable that points to another object. Interface Builder allows you to set that variable to point to another object simply by dragging a connection line from one to the other. There are two principal kinds of connections in Interface Builder:

  • Outlets are simple instance variable references from one object to another. An outlet gives one object direct access to another object. Outlets allow you to weave arbitrary graphs of objects in a nib document.

  • Actions are a Cocoa-specific duo consisting of an object reference (an outlet) and a message identifier (an Objective-C selector). Taken together, they define the object that will receive the message and exactly what message it will receive. Actions are sent almost exclusively by view objects in response to some user-initiated action, such as a mouse click, key press, touch gesture, and so on. Actions are how you "wire" your interface objects to your controller objects that will ultimately do the work.

Interface Builder outlets and actions are standard features of hundreds of preexisting classes in the Cocoa and Cocoa Touch frameworks. It's like having a huge collection of Lego blocks, ready to be connected together to form whatever you can imagine. In addition, you can add outlet properties and action methods to your own classes and then connect them to other objects exactly the same way. See the section "Custom Classes" for a complete description of creating and connecting your own objects in Interface Builder.

Note

In the sections that follow, the term "this object" means "the currently selected Interface Builder object, which is the subject of the active inspector palette."

Interface Builder provides no fewer than five different techniques for setting connections — evidence of how central connections are to the Interface Builder paradigm. I introduce them one at a time in the new few sections. All connections are the same. The different techniques are simply progressively more sophisticated shortcuts. Learn the basic ones first, and then explore the shortcuts as you spend more time making Interface Builder connections.

Connections Inspector

The connections inspector, introduced earlier, shows the outlets and actions sent by the object. Figure 13-30 shows the connections inspector for three different kinds of objects.

FIGURE 13-30

Figure 13-30. FIGURE 13-30

The Outlets group is where the outlets of the object are viewed, set, and broken. The Sent Actions group (Cocoa) or Events group (Cocoa Touch) lists the kinds of events that will trigger an action. Cocoa control objects only have one kind of event, so the list is the object that will receive the action and the action message sent. Cocoa Touch objects have many different kinds of events that cause an action message to be sent. Each one can be individually connected with a recipient/message pair. All of these groups contains connections "from" this object; in other words, object references maintained by this object that refer to other objects.

The Received Actions and Referencing Outlets groups are the complementary perspective to the Outlets, Sent Actions, and Events groups. Interface Builder thoughtfully cross-references all of the outlet references and sent actions configured from any other object in your nib document, and lists those references in these two groups. The Referencing Outlets group shows you all the other objects that have outlets connected to this object. The Received Actions group lists all of the action methods that this object defines, and shows you which objects are configured to send them.

Some events, and the Received Actions and Referencing Outlets groups, may have multiple connections for a single outlet or action. These will be collected together in the single connection. Use the disclosure triangle to expose multiple connections and manipulate them individually.

Don't confuse connections with containers. A container object has implicit references to the objects it contains. A connection is an explicit reference, identified by name, and deliberately set between two objects.

Connecting an Outlet

The simplest and most basic way to set an outlet connection is from the connections inspector of the object that defines the outlet. To set a connection, click the connection circle next to the outlet in the Outlets group and drag it to the object you want it connected to. You can choose any representation of the target object you can find in Interface Builder; you can drag it to the object in the document window (as shown), or its visual representation in a view window. The left side of Figure 13-31 shows how the docMenu outlet of the NSApplication object is being connected to an NSMenu object in the nib document.

FIGURE 13-31

Figure 13-31. FIGURE 13-31

After releasing the mouse button, the connection is established, as shown on the right of Figure 13-31. The object outlet shows the name of the object to which it is connected. When the nib document is loaded at run time, the NSApplication's docMenu outlet property will point to a new instance of NSMenu. That's all there is to making outlet connections!

Note

Interface Builder only allows connections to objects of the correct class. Interface Builder knows the class of each object, the action methods it implements, and the class of each outlet property. Interface Builder only permits connections to objects that are members of the outlet's class, and only creates action connections with messages that are implemented by the receiver. If an outlet or action doesn't appear in a list, or you think Interface Builder is ignoring your request to create a connection, it's most likely that you're trying to create an invalid connection.

Exploring and Breaking Connections

Hovering the cursor over a connection highlights the object it is connected to, also shown on the right in Figure 13-31.

To clear a connection, click the close (x) button next to the connection. You can also overwrite a connection by simply connecting the outlet to a different object. Unconnected outlets are ignored when the nib document is loaded, which typically means they will contain a nil value.

Connecting Another Object to This Object

The Referencing Outlets group contains a special New Referencing Outlet connection. It's an abstract outlet that lets you create connections to this object by setting an outlet in another object.

In Figure 13-31, the inspector palette was focused on the NSApplication object that defines the docMenu outlet. What if the inspector was focused on the NSMenu object instead? While you could switch the selection to the NSApplication object and then drag its docMenu outlet back to the NSMenu object, the New Referencing Outlet connection provides a more efficient route. The left side of Figure 13-32 shows the New Referencing Outlet being dragged from the NSMenu object to the NSApplication object.

FIGURE 13-32

Figure 13-32. FIGURE 13-32

When the mouse button is released, Interface Builder presents a menu of all possible outlets that could refer to this object, as shown in the middle of Figure 13-32. Clicking one of the outlets sets the outlet in the object you dragged to, to this object.

After being set, the connection appears in this object's Referencing Outlets group. The result is identical to having set the outlet from the NSApplication object, but you weren't forced to first change your object focus.

If you want to set that same outlet in another object, drag the connection circle next to the new referencing connection to that object. This time, Interface Builder does not prompt you to choose which outlet; the outlet will always be the same as the one previously set. Remember the distinction between the two:

  • Creating a New Referencing Connection lets you choose which outlet to set.

  • Creating a referencing connection from an existing referencing connection will set the same outlet in the chosen object that is set in the other objects.

Creating a new referencing connection will not replace any other connections to this object, so new connections will accumulate in the group — although, you might be overwriting outlets that were previously connected in some other object.

Connecting an Action

Creating an action connection is only slightly more complicated than creating an outlet connection, owing to the fact that it involves two pieces of information: the receiving object and the message to send.

You create an action connection almost exactly as you would an outlet connection. In the sent actions or events group, drag a connection circle to the receiving object, as shown in the left of Figure 13-33.

FIGURE 13-33

Figure 13-33. FIGURE 13-33

When you release the mouse button, a menu appears listing all of the action methods defined by the receiver. Select the action message you want to send and the connection is complete. The finished connection, shown on the right of Figure 13-33, displays both the name of the receiving object and the message it will receive.

Action connections are explored and broken exactly the same way as outlet connections.

Connecting an Action to This Object

Just as with the Referencing Objects group, an object's Received Actions group lists the other objects that have actions connected to this one. Unlike the Referencing Objects group, the list of actions is fixed; it's the action methods implemented by this object. An object can only receive action messages that it has implemented. (Sending a message that isn't implemented is a run time error.)

It works pretty much the same way the Referencing Objects group does. To configure an object to send an action to this object, select the connection circle next to the action that you want this object to receive, and than drag it to the object that you want to send it.

If the sender is a Cocoa object, you're done. If it's a Cocoa Touch object that generates multiple events, you must now select which event you want to trigger that message, as shown in Figure 13-34.

FIGURE 13-34

Figure 13-34. FIGURE 13-34

Pop-Up Connections Panel

Technically, you've learned everything you need to know to create, explore, dissolve, and cross-reference connections in your nib document, but creating connections is such a common activity that Interface Builder provides a number of additional shortcuts.

In the earlier techniques you set connections by:

  1. Selecting an object.

  2. Selecting the connections inspector panel.

  3. Dragging the desired outlet or action to the target object.

Pop-up connection panels, shown in Figure 13-35, eliminate step 2 of that procedure. Pop-up connection panels are floating panels that appear over an object when you Right/Control-click an object.

FIGURE 13-35

Figure 13-35. FIGURE 13-35

Click the close button or press the Esc key to dismiss the panel.

A pop-up connections panel is identical to the connections inspector for that object — the only difference is that you didn't have to open the connections inspector. All of the controls work exactly the way they do in the connections inspector, with a couple of added features.

The first is the "connect behind" feature. If you hover the cursor over the panel as you begin to make a connection, the panel will fade away, as shown in Figure 13-36. This allows you to make connections to objects obscured by the pop-up connections panel.

The second feature appears if the object you've chosen is in an object hierarchy. Figure 13-37 shows a table view object. The table is contained within a scroll view and a window, and contains a column view (among others).

FIGURE 13-36

Figure 13-36. FIGURE 13-36

FIGURE 13-37

Figure 13-37. FIGURE 13-37

The pop-up connection panel for the table includes a small set of arrow buttons at the right edge of the panel's title. Clicking those arrows, as shown in Figure 13-37, brings up a menu of the objects in the hierarchy at the coordinate that you originally clicked. This is the same sequence of objects that you would get by "drilling down" at that point in the interface.

Selecting one of the other objects in the menu refocuses the pop-up connections panel to that object, allowing you Right-click one object and then set a connection for one of its containers or subobjects.

Quick Connection

A quick connection is Interface Builder shorthand. It creates a connection between two objects with a single gesture. To create a connection (outlet or action) between any two objects:

  1. Right/Control-click the source object.

  2. Hold down the mouse button and drag to the destination object, as shown in Figure 13-38.

  3. Release the mouse button.

  4. Select the outlet or action to connect.

The direction of the drag is the same that you use in the Outlets, Sent Actions, and Events groups:

  • Drag from the object with the outlet to the object you want the outlet connected to.

  • Drag from the object that sends an action to the object that implements the action.

When you release the mouse button, a menu appears with every outlet and action connection that's possible between those two objects. Select the outlet or action and the connection is complete.

FIGURE 13-38

Figure 13-38. FIGURE 13-38

There's a limitation when making quick connections from Cocoa Touch objects. When you create an action connection, the action is always connected to the Touch Up Inside event. In other words, you can't use a quick connection to select both the event to connect to and the action message to send. Use the pop-up connections panel if you need to connect an action to some event other than Touch Up Inside.

The real power of connections and actions emerges when you define your own outlets and action messages. This is explained in the next section.

CUSTOM CLASSES

Interface Builder would only be mildly useful if all it could do was create, configure, and connect instances of the predefined framework objects found in the library palette. The power of Interface Builder explodes when you can define your own classes, outlets, and actions, and then use Interface Builder to create instances of your custom objects, configure them, and then connect them just like any other nib document object. Using Interface Builder you can:

  • Add instances of your custom classes to a nib document.

  • Define outlets in your custom classes that will be recognized by Interface Builder.

  • Define action methods in your custom classes that will be recognized by Interface Builder.

Interface Builder recognizes when a nib document belongs to an open Xcode project. It then interfaces with Xcode to extract information about your class definitions and incorporate that into the document. It does this quickly, quietly, and transparently in the background. All you have to do is define your class. By the time you've saved your class files and switched to Interface Builder, your class definitions will have been assimilated and are ready to instantiate, configure, and connect.

Warning

Save your source files! Interface Builder only considers class definition files that have been saved to disk. Get into the habit of saving all files (Option+Command+S) before switching from Xcode to Interface Builder. This ensures that Interface Builder has the most current knowledge about your project's class definitions. If a class or property doesn't appear in Interface Builder, make sure your source files don't have any syntax errors. Also make sure the Synchronize With Xcode option is checked in the Interface Builder preferences.

Creating an Instance of a Custom Class

You can add an instance of practically any class you've defined in your project to a nib document. To create an instance of a class, follow these steps:

  1. Define the class in Xcode.

  2. Save the interface file(s) that define the class.

  3. In Interface Builder, find the generic superclass object for your class in the library palette and create an instance of it.

  4. Select the new object.

  5. In the identity inspector, change the class of the object from its generic class (for example, NSObject) to your specific class (such as MyObject).

Figure 13-39 shows the class of a generic NSObject being changed to MyAppDelegate, a custom class defined in the active Xcode project.

FIGURE 13-39

Figure 13-39. FIGURE 13-39

At run time, an instance of your class is created instead of the generic object that was in the library palette. The library palette object you choose will depend on the superclass of your custom object. In general, follow this rule: choose the most specific class in the library palette that your custom class inherits from.

For example, if your class is a custom subclass of NSTokenField, then create an NSTokenField object before changing its class to yours. Interface Builder understands that your object is a subclass of NSTokenField and will present all of the attributes, connections, and actions defined by its superclasses (NSTokenField, NSTextField, NSControl, and NSView), in addition to any outlets and action methods that your subclass defines.

The library palette provides a short list of truly generic classes that — as themselves — don't do much of anything useful. They are included in the library palette solely so you can create custom subclasses of them:

GENERIC LIBRARY OBJECT

CLASS

Object or External Object

NSObject

View Controller

NSViewController or UIViewController

Custom View

NSView

View

UIView

Create an (External) Object when you subclass NSObject directly, or subclass any class that isn't represented in the library palette.

Note

Anything means anything. Interface Builder will let you change the class of a generic NSObject instance to any class that exists, even ones defined in the frameworks. There's no NSMutableArray object in the library palette, but there's nothing stopping you from creating a generic Object instance, changing its class to NSMutableArray, and connecting it to an outlet. At run time, the nib document will gladly create and connect an instance of NSMutableArray.

The most obvious applications of custom objects in a nib document are to:

  • Create a controller object and connect it to all of its view objects.

  • Create a custom delegate object and connect it to the delegate outlet of whatever objects (application, windows, tables, and so on) it should augment.

  • Create custom subclasses of NSView or UIView and position them in superviews.

I'm sure you can think of a million other uses. The basic principle is this:

  • If you need to create an object that will connect to, or be connected from, other objects in a nib document, consider creating the object in the nib document.

Now that you know how to create instances of your own classes, or replace instances of library objects with your own custom subclasses, you'll want to start creating custom connections. To do that, you need to define outlets and actions in your class.

Adding Custom Outlets to Your Class

Adding outlets to your own class is simple:

  1. Declare a settable property (or instance variable) that stores an object pointer.

  2. Include the IBOutlet modifier in the property's type.

All IBOutlet marked properties will appear as outlets in the object's connections inspector. In Figure 13-40, the class MyAppController declares an aboutWindow property that refers to an NSWindow object.

FIGURE 13-40

Figure 13-40. FIGURE 13-40

If you're using Objective-C 2.0, the preferred place to declare a property as an IBOutlet is in the @property directive, as was shown in Figure 13-40. You can still use the IBOutlet type modifier in the instance variable declaration if you're not using Objective 2.0 or do not include a @property directive. Interface Builder will recognize either.

I should note that the IBOutlet type really isn't a type; it's just tag for Interface Builder. As of this writing, IBOutlet is a preprocessor macro that's replaced with nothing at compile time.

Warning

Renaming a property by editing its declaration can confuse Interface Builder. For example, if you renamed aboutWindow to creditsWindow after having connected aboutWindow to the NSWindow object in your nib document, the nib document will now contain a connection to a non-existent property. (In Interface Builder this will appear as a connection with a warning symbol next to it.) Rename outlet properties and action methods using the Refactoring tool (see Chapter 10), which can find and rename any nib document references as well.

Adding Custom Actions to Your Class

Creating actions is about as simple as creating outlets:

  1. Define a method that conforms to the prototype —(void)anyMethod:(id)sender.

    1. The method must have a void return type.

    2. The method should expect a single object reference as its only parameter.

  2. Replace the return type in the declaration with IBAction, as in -(IBAction)myAction:(id)sender.

In Figure 13-41, an action method has been added to MyAppDelegate. The action appears in the connections inspector, where it can be connected to view objects. In this case, the button's action is configured to send MyAppDelegate a -closeAboutWindow: message when the user clicked the button.

FIGURE 13-41

Figure 13-41. FIGURE 13-41

When your object receives an action, the sender parameter refers to the object that sent the message, providing it some context. In the case shown in Figure 13-41, sender refers to the "OK" NSButton object the user clicked. Note that this is a convention of the Cocoa framework, it's not a strict requirement. If you send action messages yourself, you can pass some other object, or even nil, as you see fit. Many action methods simply ignore the sender parameter.

Initializing Custom Objects at Run Time

For the most part, nib files contain archived (serialized) versions of Cocoa objects, but the nib file loading mechanism makes some concessions, and relaxes a few of the normal rules of object archiving in order to make the nib file content as flexible and convenient as possible. Specifically:

  • Custom objects in a nib file are not required to conform to NSCoding protocol.

  • Most custom objects are initialized using a simple — init method, rather than the formal — initWithCoder: used to decode archived objects.

This means that your custom objects don't have to conform to NSCoding in order to be instantiated from a nib file. It also means that any object that can be validly constructed with [[Class alloc] init] can be added to a nib file.

The following table describes exactly how objects in a nib document are constructed at run time:

OBJECT TYPE

DESCRIPTION

INITIALIZER

Custom View Objects

A custom subclass of NSView.

-initWithFrame:

Non-View Custom Objects

A custom subclass of NSObject that is not a subclass of NSView.

-init

Interface Builder Classes

Any class that appears in the library palette, or a custom subclass of an object that appears in the library palette.

-initWithCoder:

Constructing custom view objects with -initWithFrame: makes them compatible with the normal programmatic initialization of NSView objects (-initWithFrame: is NSView's designated initializer).

All non-view custom objects are constructed with the standard -init message. This means that you don't have to make your class conform to NSCoding in order to include it in a nib file.

The objects defined in the Interface Builder palette all conform to NSCoding and are initialized using the standard decoding method -initWithCoder:. The attribute values that you set in the inspector panels are decoded from the archive data stream.

If you create a custom subclass of an Interface Builder object that's constructed with -initWithCoder:, your class will initialize itself with -initWithCoder: too. That's the only way that attributes set for its superclasses can be read at run time. Custom NSObject subclasses can be initialized with -init because there are no editable properties for custom classes — only outlets and actions. Nothing needs to be read from the archive stream during initialization.

After the objects in the nib file are constructed, two more things happen:

  1. All of the connections are set.

  2. Every object receives an -awakeFromNib message.

If your object needs to perform any additional initialization, especially any initialization that depends on connections, it should implement a -(void)awakeFromNib method.

PLACEHOLDER OBJECTS

A subject I've been avoiding is what those other, mysterious, objects in your nib document — like File's Owner and First Responder — are. These are special placeholder objects. They represent objects that will exist before the nib document is loaded.

Now that you understand connections and custom objects, explaining the role of placeholder objects is simple. Placeholder objects allow you to create connections between the objects in your nib document and objects that already exist in your application. This allows you to create connections to objects outside the set of objects in the nib document.

The most important placeholders to understand are the File's Owner and the First Responder. The remaining placeholders represent miscellaneous singleton objects supplied by the frameworks.

File's Owner

When a nib file is loaded, one object is designated as its owner. What object that is depends on who's doing the loading. The following table lists the owner objects of common nib files loaded by the Cocoa frameworks:

File's Owner

FILE'S OWNER

NIB DOCUMENT

NSApplication

Main application interface

NSDocument

Document window

UIViewController

Interface view

For example, when you design a UIVewController object, the controller is associated with a nib document. When the controller needs to construct its view objects, it loads its nib document passing itself as the file's owner. In the nib document, the class of the File's Owner object is UIViewController, exposing all the outlets and actions defined by your controller to the nib document objects. For example, when the nib is loaded, the controller's view outlet is connected to the new UIView object that contains the controller's interface. After the nib file is loaded — as if by magic — the UIViewController now has an instance variable that points to a complete set of interface objects.

You can exploit the nib file's owner object to great effect in two ways. The first is use the identity inspector to change the class of the File's Owner object to your custom subclass. This happens naturally with NSDocument and UIViewController objects — you virtually never use the base class of these objects. Once you've changed the File's Owner to your subclass, your outlet and actions appear, ready to be connected.

The other approach is to load the nib file yourself. When you load a nib file with a message like +[NSBundle loadNibNamed:owner:], you can pass whatever object you want as the file's owner. Thus, you have the ultimate control on what object is available to make connections.

The caveat under all circumstances is that the actual class of the file's owner must agree with the class in the identity inspector of the nib document. When you're making connections in the nib document, the class of the file's owner is assumed to be correct. It's up to you to make sure the actual owner is a compatible object at run time.

First Responder

The first responder is a placeholder object used to make action connections. The Cocoa frameworks have a concept called the responder chain. Briefly, it's a list of active view objects that's determined by the current state of the user interface. Fluctuations in the chain affect what actions are acted upon, and what objects receive those actions.

First Responder

When you connect an action to a specific object, you create an explicit connection. The object will always send the action to the object it's connected to; there's no ambiguity.

An object that has a message identifier (Objective-C selector) but no object reference (nil) is said to be connected to the first responder. It really isn't connected to anything at all, but at run time the recipient of the action will be determined dynamically by passing the message to the current responder chain. (If you're curious, an object with no action connection has a NULL message identifier.)

You create a first responder connection by connecting the action of an object to — yes, you guessed it — the First Responder placeholder. When you do, it creates a connection with a valid message identifier and a nil object reference.

The conundrum for the first responder placeholder object is that it doesn't know what actions the dynamic responder chain actually responds to — that's determined at run time. So, the first responder placeholder object simply pretends to respond to every action message Interface Builder knows about. When you connect an object to the first responder, you'll see a huge list of actions. This is perfectly normal. Select the action that you expect the chain to respond to at run time.

Other Placeholders

Any other placeholder objects that you find will invariably be singleton objects supplied by the framework. The most common are:

Other Placeholders

PLACEHOLDER

OBJECT

Application

The single NSApplication object created for every Cocoa application.

Font Manager

The single instance of NSFontManager returned by +[NSFontManager sharedFontManager].

Shared User Defaults

An instance of NSUserDefaultsController for creating bindings directly to the user defaults.

If the single NSApplication object is actually an instance of your NSApplication subclass, you can change the class of the placeholder object in the identity inspector. This gives your nib document direct access to the custom outlets and actions in your application.

Note

It's far more common to create your own application delegate object, implement your custom outlets and actions there, create an instance of your delegate in the nib document, and then connect the delegate object to the delegate outlet of the vanilla NSApplication object.

DECOMPOSING AN INTERFACE

This isn't about feature rot, but it does concern nib document bloat. It's easy to add new interface elements (utility windows, subviews, alternate views) to an existing nib document, so we often do. The result can be a nib document that loads many objects that the application doesn't need immediately. This isn't typically a problem for desktop applications, but on small hand-held devices (like iPhones and iPods), nib document bloat can slow initial load times and degrade the perceived performance of your application.

To help you break up large nib documents, Interface Builder provides the File

DECOMPOSING AN INTERFACE

In Figure 13-42, a view controller's nib document defines a view with a single table. It also defines a number of table view cell layouts that are employed based on table content. Loading all of these cell views takes time, even though the table might end up using only one or two.

FIGURE 13-42

Figure 13-42. FIGURE 13-42

After decomposing the interface, Interface Builder has created nine new nib document windows. The ones that contain a single table view cell layout can now be saved and added to the project. The original copies of the individual cell views would be deleted and the code in the controller would be rewritten to lazily load each table cell view as needed. The result is a table view that loads quicker, and may potentially use less memory.

IMPORTING AND EXPORTING CLASSES

Until recently, it was possible to define new classes, complete with outlets and actions, entirely within Interface Builder. The idea was that you could design your interface, classes, connections, and actions before ever writing a single line of code.

Thankfully, those days are behind us. The idea of designing classes in Interface Builder might seem like a nice one, but it falls victim to the problems that plague other design tools that generate code: how to keep the classes you define in the interface design tool in synchronization with the source code of the application. If that fails, you end up with a nib document that contains classes, outlets, and actions that don't actually exist in the application.

The modern incarnation of Interface Builder eliminates these problems by eliminating round-trip editing. You define your classes, outlets, and actions in the Xcode project, and then switch to Interface Builder to create, configure, and connect them together. It's demonstrably the fastest and easiest way to work, and it keeps your project in perfect synchronization with your nib document.

Nevertheless, a few vestiges of the old methodology still lurk in Interface Builder. The commands File

IMPORTING AND EXPORTING CLASSES

To export a class, choose one or more objects in a nib document and choose File

IMPORTING AND EXPORTING CLASSES

To import a class, choose File

IMPORTING AND EXPORTING CLASSES

NIB DOCUMENT FORMATS

Both Xcode and Cocoa have evolved over the years. The format of nib documents has changed to accommodate that evolution, adding new features and capabilities — along with compatibility issues. The biggest recent change in Interface Builder has been the support for a new XML-based nib document. The XML document is compiled to produce the binary NIB file that's actually deployed with your application.

Choose the Window

NIB DOCUMENT FORMATS
FIGURE 13-43

Figure 13-43. FIGURE 13-43

Here you can set and verify a number of different compatibility settings.

Document Format

The Document Format tells you what kind of format the nib document uses. The basic types are Cocoa, Cocoa Touch, and Carbon. If the nib document was created recently, it will probably be in the new XML (XIB) format. If not, it will be in one of the legacy (NIB) file formats.

You can't change the type of a nib document; the type is fixed when the document is created.

XIB nib documents are stored as XML documents. When your application is built, the XML representation is compiled (via the ibtool) into a binary form suitable for deployment. If you are still using one of the legacy nib document bundles, the binary portion of the nib document is simply copied into your application's bundle.

You can use the ibtool command-line tool to extract information, convert between storage formats, and perform other manipulations. For example, the following command converts the legacy MainMenu.nib bundle into a modern XIB document:

ibtool --upgrade MainMenu.nib --write NewMainMenu.xib

Use Xcode's Help

Document Format

Document Locking

The Document Locking controls are exactly the same as those in the identity inspector, but apply to every object in the document. If you've individually locked some objects, the Reset All Objects button will clear all locked objects in the nib.

Checking Deployment Compatibility

The Deployment Target performs some basic deployment compatibility checks on the objects in your nib document. As operating systems evolve, so do the features and capabilities of the objects in your nib document. Setting the minimum anticipated deployment target for the nib document presents any possible conflicts or incompatibilities that might exist when the nib document is loaded on an older system, as shown in Figure 13-44.

FIGURE 13-44

Figure 13-44. FIGURE 13-44

Compatibility conflicts can be notes, warnings, or errors. In Figure 13-44, the error tells you that the MKMapView class did not exist prior to iPhone OS 3.0. If this nib document were loaded using an older iPhone OS, it would fail to create the necessary objects, possibly failing to load altogether. The solution would be to either restrict this application to iPhone OS 3.0 or later, or prepare two nib documents: one to load on iPhone OS 3.0 and a second one (without an instance of MKMapView) for earlier systems.

Keeping Backward Compatibility

The Development Target setting lets you define the earliest version of Interface Builder that you want the nib document to be compatible with. This is important if you are working on projects that are being maintained using an older version of Xcode. Though it would be nice if everyone were always using the latest version of Xcode, sometimes that's not practical. Setting this option warns you if any properties of the nib document are incompatible with earlier versions.

CUSTOMIZING INTERFACE BUILDER

Interface Builder can be customized in a few small, and one very significant, ways.

Customizing the Library Palette

There are number of ways to customize the look and content of the library palette. The typical library palette, shown on the left in Figure 13-45, has three panes: the library group, the objects in the selected groups, and a description of the selected object.

You can collapse the group list down to single pop-up menu by dragging the upper pane separator to its highest position. You can eliminate the description pane by dragging the lower separator to its lowest position. Both are shown on the right in Figure 13-45.

FIGURE 13-45

Figure 13-45. FIGURE 13-45

Choose the action menu at the bottom, or Right/Control-click the objects list, to choose the display style. You can choose from very compact to extremely verbose listings.

Creating Custom Groups

If you have a number of objects that you use regularly, you can collect them in a custom group. Choose New Group from the action menu at the bottom of the palette and give your group a descriptive name. Items can be added to your group by dragging them from the other library groups into your group. To remove items, select them and choose the Remove From Group command. To delete the entire group, choose Remove Group.

You can also create smart groups using the New Smart Group command. A smart group collects objects automatically based on some criteria that you define, as shown in Figure 13-46.

FIGURE 13-46

Figure 13-46. FIGURE 13-46

Saving Custom Objects

You can also preconfigure one or more objects, and then save them in the library palette for use again later. To save custom objects:

  1. Create an interface with one or more objects.

  2. Customize, configure, and connect them.

  3. Drag the objects from your nib document back into either the Custom Objects group or your own custom group, as shown on the left in Figure 13-47.

  4. Provide a name and some details for the saved objects, as shown on the right in Figure 13-47.

The custom object, or objects, are saved in the library and can be re-created like any standard object. To delete a custom object, select it and choose Remove From Library in either the action menu or by Right/Control-clicking the item.

FIGURE 13-47

Figure 13-47. FIGURE 13-47

Customizing Document and Compatibility Checking

The compatibility checks that Interface Builder performs are done based on known incompatibilities, common practices, and Apple's recommendations. You might not agree with these recommendations, their perceived severity, or they might not apply to your projects. You can edit the error and compatibility checks in the Interface Builder preferences, as shown in Figure 13-48.

The Alerts panel of the Interface Builder preferences (Interface Builder

Customizing Document and Compatibility Checking
FIGURE 13-48

Figure 13-48. FIGURE 13-48

At the bottom is the Alert When Saving option. Set it to the minimum severity that you want to be alerted to every time you save your nib document.

Developing Custom Interface Builder Objects

Xcode and Interface Builder make it very easy to define and create custom objects. It's almost trivial to add outlets and actions to those objects, which you can connect to other objects in the nib document, but three things are still lacking:

  • You can't define new attributes for your custom objects, or edit your object properties using the attributes inspector.

  • Your custom objects can't define actions that they send.

  • You can't preview how your custom view object will look in Interface Builder.

The solution to these, and other, limitations is to create an Interface Builder Plug-In. An Interface Builder Plug-In, or just plug-in for short, is a resource bundle that you create — probably as a separate project — that defines one or more custom objects that will appear in the Interface Builder library palette right alongside all of the standard objects. In fact, most of the objects you seein Interface Builder's library palette are provided by plug-ins. You can see (and change) those plug-ins in the Plug-Ins panel of Interface Builder's preferences window, as shown in Figure 13-49.

A plug-in object can have attributes, editable using the attributes panel. It can have a simulated representation, so you can see how it will look in Interface Builder, and it can embody many of the advanced features of the built-in objects: intelligent alignment guides, embedded objects, size restrictions, and so on.

If you decide you want to create your own Interface Builder Plug-In, start with the Interface Builder Plug-In template in Xcode. You'll also find the IBKit Interface Builder templates convenient for adding additional object definitions to an existing plug-in. A rough sketch of how an Interface Builder Plug-In is developed is as follows:

FIGURE 13-49

Figure 13-49. FIGURE 13-49

  1. Create an Interface Builder Plug-In project.

  2. Define a nib document that will present the object in the library palette.

  3. Define a nib document that contains the controls that will appear in its attributes panel.

  4. Prepare an abstract description of the object that describes its properties, outlets, and actions.

  5. Write an object simulator that Interface Builder will use to draw instances of your object in Interface Builder.

  6. Build your plug-in and add the finished product in the Plug-Ins preferences panel.

These steps, and many other details, are described in the Interface Builder Plug-in Programming Guide, included in the developer tools documentation.

SUMMARY

Interface Builder provides a rich environment for designing menus and windows, but it goes beyond that, letting you define classes, create custom objects, and connect those objects together at runtime, all without having to write a single line of code.

You'll quickly become addicted to designing your application interfaces and object relationships using Interface Builder. If you like seeing your interface design graphically, you'll enjoy the next chapter, where you learn how to visualize your classes graphically.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset