Managing Multiple Nibs

When a Cocoa application starts up, all of the objects stored in its main nib are loaded into memory and initialized. This takes time (the more objects, the more time), and until the nib is loaded, your application can’t do anything else. This can be real drag, especially if your program doesn’t need most of the objects in the main nib for normal operation. For this reason, Cocoa lets you take objects that you don’t use often and place them in separate nibs. You can arrange for these auxiliary nibs to be loaded only when they are needed.

Auxiliary nibs should be used for most panels that do not need to be displayed when your program first starts up. Instead, the files are loaded the first time that the panel is needed. Once the panel is loaded, it is resident in your computer’s memory — additional attempts to make the panel display go much faster.

Now we’ll arrange for our Calculator application to use a separate nib for its About box. This will consist of three steps:

  1. Creating the new nib that contains the About box

  2. Modifying the Controller class to load this new nib (and thereby display the About box)

  3. Modifying the Calculator’s MainMenu.nib accordingly

For pedagogical reasons, we’ll perform these steps in the order (ii), then (iii), and finally (i).

Modifying the Controller Class

To start, we’ll modify the Controller object to add two things:

aboutPanel

A new outlet that holds the id of the About box

showAboutPanel:

A new action method that displays the About box

You might think that the easiest way to create the new outlet and action method is to add them in IB’s inspector window, as we did in the previous chapter. You can do this. However, because we have added code to the Controller.h and Controller.m class files, if you add the outlet and action methods in IB, you will need to use Apple’s File Merge utility to merge the changes that you made in these files with the changes that IB makes. This can be somewhat complicated, and if you make a mistake, you will lose all of the specialized coding that you have added so far!

Instead, we believe that the easiest way to add new outlets and action methods to the Controller class is to use a text editor to add them directly to the Controller.h and Controller.m class files, and then use IB’s Classes Read Files command to read them into IB’s internal description of the class. The new outlet and action will then appear in IB’s Controller class inspector, and we’ll be able to use them to make connections with user interface objects. (Recall that we parsed an outlet from the Controller.h file into IB in the previous chapter; here we’ll parse a method in a similar fashion.)

  1. Back in PB, insert the two lines shown here in bold into Controller.h, and save the file:

    @interface Controller : NSObject
    {
        IBOutlet id readout;
        BOOL        enterFlag;
        BOOL        yFlag;
        int         operation;
        double      X;
        double      Y;    IBOutlet id aboutPanel;
    }
    - (IBAction)clear:(id)sender;
    - (IBAction)clearAll:(id)sender;
    - (IBAction)enterDigit:(id)sender;
    - (IBAction)enterOp:(id)sender;
    - (void)displayX;
    - (IBAction)doUnaryMinus:(id)sender;- (IBAction)showAboutPanel:(id)sender;
    @end

The aboutPanel outlet will eventually be set to the id of our new About box object. The showAboutPanel: action method will be coded to display the About box in response to the user’s choosing the Calculator About Calculator menu command.

  1. Make sure you save the edited Controller.h file at this point, because IB will read the class interface file from disk, not from your edited but unsaved copy.

  2. Now double-click the MainMenu.nib resource in PB to open the interface in IB. (Following that, you again might want to choose IB’s Hide Others menu item to simplify your screen).

  3. Select the Controller class (under NSObject) under the Classes tab in IB’s MainMenu.nib window and choose IB’s Classes Read Files menu item.

  4. Double-click Controller.h in the Read Files panel that opens to parse the new definition of the Controller class from the updated Controller.h file on disk.

  5. Type Command-1 to display IB’s Attributes Info dialog; you should see the new aboutPanel outlet and the new showAboutPanel: action method, as shown in Figure 6-5. (If you don’t see them, you probably didn’t save the Controller.h file after editing).

New outlet (left) and action method (right) in Controller class

Figure 6-5. New outlet (left) and action method (right) in Controller class

  1. Back in PB, insert the entire new showAboutPanel: method, shown here in bold, into Controller.m. We suggest that you place it just before the @end directive.

                            - (IBAction)showAboutPanel:(id)sender
                            {
                               if (aboutPanel == nil) {
                                 if (![NSBundle loadNibNamed:@"AboutPanel.nib" owner:self] ) {
                                   NSLog(@"Load of AboutPanel.nib failed");
                                   return;
                                 }
                               }
                                [aboutPanel makeKeyAndOrderFront: nil];
                            }

Every Objective-C instance variable is initialized to nil (0) when an object is created.[13] When the Calculator application starts up, the aboutPanel outlet in the Controller instance will not be explicitly set, so its value will be nil. Thus, when the showAboutPanel: method is invoked the first time, the conditional if statement will cause the loadNibNamed:owner: message to be sent to the NSBundle class.

A bundle in Cocoa is a collection of files in a folder that is used to store dynamically loaded code, icons, sounds, objects, and/or other kinds of information. A nib is a special kind of bundle that is used by IB to store user interfaces. Applications are another special kind of bundle that are created by PB and used by the Finder to put together all of the files that go into an application. Frameworks and IB palettes are additional examples of bundles.

The call to the loadNibNamed:owner: method loads the nib bundle containing the About box (which we’ll create later in this chapter) from the nib AboutPanel.nib. When the nib is loaded, it automatically initializes the aboutPanel outlet of its owner to the id of the About box. (We’ll show you how to create the About box and set up this initialization a bit later.) Finally, the showAboutPanel: method will send the About box object the makeKeyAndOrderFront: message, which makes the About box the key window and brings it to the front of the window display list (making it visible). If something goes wrong with the loading, the NSLog( ) [14] function will display an error message in the system console and in PB’s Run pane if the application is run from PB. This can be very useful in debugging.

The second time the showAboutPanel: method is called, the aboutPanel outlet will already be initialized. Thus, the statement sending the loadNibNamed:owner: message will be skipped, preventing a second copy of the nib from being loaded. Because the nib that we loaded the first time through is still in memory, the About box will be displayed without the loading delay.

Apple’s “Aqua Interface Guidelines” say that bringing up a panel should be a safe and reversible option. A user should be able to make the panel disappear by clicking a cancel or close button without any ill effects for the application. Our About box will meet this requirement.

Modifying the Main Calculator Nib

Next we’ll modify the About Calculator menu item command in the Calculator’s main menu so that it invokes our showAboutPanel: method.

As we saw earlier in this chapter, the Cocoa development environment gives every new Cocoa application a built-in About box. This panel is displayed by the NSApplication object when it receives the orderFrontStandardAboutPanel: message. To have our application display our custom About box (which we haven’t created yet), we’ll need to change the About Calculator menu item so that it invokes our method, instead of the default method.

To do this, follow these steps:

  1. Back in IB, click Calculator in the Calculator main menu to open the submenu.

  2. Select the About Calculator menu item.

  3. Type Command-2 to display the Connections Info dialog for the NSMenuItem, as shown earlier in Figure 6-2.

  4. Make sure that the orderFrontStandardAboutPanel: action method is highlighted in the Connections inspector and then click the Disconnect button to remove the default connection. The dimple next to the method should disappear.

  5. Control-drag from the About Calculator menu item to the Controller object in the MainMenu.nib window to create a new connection, as shown in Figure 6-6.

New connection between About Calculator menu item and Controller instance

Figure 6-6. New connection between About Calculator menu item and Controller instance

  1. Select the showAboutPanel: action in the NSMenuItem Info dialog (see Figure 6-6), and then click the Connect button at the bottom of the dialog. The Connect button will become a Disconnect button, as shown in Figure 6-6. (You can also double-click the action method.)

We have now arranged for the About Calculator menu command to invoke the Controller’s showAboutPanel: action method.

There is one other modification that we should make to the Calculator menu, concerning the menu command that brings up a Preferences panel. Because our Calculator application doesn’t have a Preferences panel, we should remove this menu item.

  1. Still in IB, select the Calculators Preferences menu item by clicking it once.

  2. Type Command-X to cut the menu item from the menu. Your menu should now look like the one in Figure 6-7.

Newly configured Calculator application menu in IB (no Preferences item)

Figure 6-7. Newly configured Calculator application menu in IB (no Preferences item)

  1. Type Command-S to save the MainMenu.nib file.

Creating the About Box Nib

To complete our About box addition, we will create a separate nib for the About box. This nib will be loaded by the loadNibNamed:owner: message that the Controller’s showAboutPanel: method sends to the NSApplication object.

  1. Choose IB’s File New command. IB’s Starting Point panel will appear.

  2. Select Cocoa Empty, as shown in Figure 6-8, and click New.

Creating a new empty nib in IB

Figure 6-8. Creating a new empty nib in IB

Note that there are now two Nib File windows at the lower left of the screen, one for MainMenu.nib and the other (“Untitled”) for the new nib that we created.

  1. Type Command-S to save this new nib, and you’ll see a “Save as” sheet slide out from under the title bar.

  2. If necessary, click the down arrow button to reveal the full “Save as” sheet. Find the folder Calculator/English.lproj (the English-language project directory of the Calculator source code), shown in Figure 6-9.

Saving a new nib for the About box in IB

Figure 6-9. Saving a new nib for the About box in IB

  1. Save the new nib as AboutPanel.nib. Before saving, IB will ask you if you want to add the new nib to the Calculator project, as shown in Figure 6-10. Click Add.

Adding the new AboutPanel.nib to the Calculator project

Figure 6-10. Adding the new AboutPanel.nib to the Calculator project

After you add the new nib, note that the name in the title bar of the second Nib File window changes to AboutPanel.nib, as shown in Figure 6-11. Note also that there are only two instance objects, File’s Owner and First Responder, in the new nib (compare with MainMenu.nib in Figure 6-11). Because IB knows this is an empty auxiliary nib, it doesn’t automatically provide you with MainMenu and Window instances, as it did for the main nib. Clearly, another MainMenu object is not needed. Also, if you activate PB, you’ll notice that AboutPanel.nib has been added to the Calculator project as a resource, alongside MainMenu.nib and InfoPlist.strings. Thus, when the Calculator application is built, AboutPanel.nib will automatically be copied into the Calculator.app application bundle.

New AboutPanel.nib window (left)

Figure 6-11. New AboutPanel.nib window (left)

  1. If PB is active, double-click AboutPanel.nib in PB’s main window to reactivate AboutPanel.nib in IB. (If you double-click any file in PB’s Groups & Files pane, PB will open that file in the appropriate application.) This step may not be necessary.

  2. Back in IB, make sure the AboutPanel.nib window is active (or key). To simplify the screen, we recommend that you minimize the MainMenu.nib window and hide the other applications.

  3. Click the Cocoa-Windows button (which should be the fourth button from the left) in IB’s Palettes window toolbar. See Figure 6-12.

Cocoa-Windows palette in IB

Figure 6-12. Cocoa-Windows palette in IB

  1. Drag the icon with the Panel label from the Cocoa-Windows palette and drop it in the AboutPanel.nib window (you can also drop it on the desktop). This will create an empty panel with the title “Panel” and will add the panel to the AboutPanel.nib nib. See Figure 6-13.

New panel (right) and updated AboutPanel.nib with panel icon

Figure 6-13. New panel (right) and updated AboutPanel.nib with panel icon

  1. Click anywhere inside the new panel to select it, then type Command-1 to bring up the NSWindow Attributes Info dialog (NSPanel is a subclass of NSWindow).

  2. Change the title of the panel to “About the Calculator” in the Info dialog.

  3. Click the Cocoa-Views button (which should be the second one from the left) at the top of IB’s Palettes window.

  4. Customize the panel’s text by dragging and dropping text icons (e.g., System Font Text) from the Cocoa-Views palette into the panel.[15] Type Command-T to bring up the Font panel to change the size, etc. of the type. See what we did in Figure 6-14. (Your About box won’t look exactly the same as our screen shot yet, but it doesn’t matter.)

Newly customized About box

Figure 6-14. Newly customized About box

  1. Now drag the horizontal-line icon from below the radio buttons in the Cocoa-Views palette and drop it in the new panel. Resize it and change its location to be a separator, as shown in Figure 6-14. Also, resize the panel itself as appropriate.

Note that we’ve left some space at the upper right of the “About the Calculator” panel. We’ll use that space to place our application icon before the end of the chapter.

Recall that we want the Controller instance to load AboutPanel.nib when the user chooses our Calculator’s Calculator About Calculator menu command. We’ve already set up the target/action connection from the menu command to the Controller, but we have not yet set up any communication between the Controller and the About box. The About box is part of the separate AboutPanel.nib, and this nib doesn’t even “know” that a Controller class exists. You can see this by looking at the subclasses of NSObject under the AboutPanel.nib Classes tab — there’s no Controller class. We’ll set up the required linkage between the new nib and the Controller in the next few steps.

  1. Select the NSObject class in the Classes pane in the AboutPanel.nib window.

Note that the Controller class does not appear (recall that it did show up in the MainMenu.nib window). To change this, we’ll make IB read the Controller.h information into AboutPanel.nib.

  1. Choose the Classes Read Files menu command, and the Read Files dialog will open.

  2. Browse the filesystem to select the Controller.h file (under ~/Calculator) in the Read Files panel, then click the Parse button.

The Controller class should now show up in the AboutPanel.nib window, as shown in Figure 6-15. Now AboutPanel.nib knows about the Controller class outlets and action methods, and it also knows that it is a subclass of NSObject. Of course, all of this information is contained in Controller.h.

Controller class in AboutPanel.nib window

Figure 6-15. Controller class in AboutPanel.nib window

Alternatively, you could have informed AboutPanel.nib about the Controller class by simply dragging the Controller.h file icon from the Finder or PB and dropping it into the AboutPanel.nib window. When you do this, IB will automatically parse the Controller class definition on disk and insert the Controller class into the AboutPanel.nib class hierarchy. We’ll use this quicker technique in subsequent chapters.

We still need to make a connection from the Controller instance (created by MainMenu.nib) to the About box object (created by AboutPanel.nib) in order to initialize the Controller’s aboutPanel outlet. We cannot do this using a different Controller instance instantiated by AboutPanel.nib — we must use the instance instantiated by MainMenu.nib, because that’s the one that controls the running Calculator application! To do this, we will use the File’s Owner icon in AboutPanel.nib. The File’s Owner is an object that “owns” a nib.[16] It’s the argument that is passed to the NSBundle class when the nib file is loaded. We’ve already arranged for this argument to be the id of the Controller object that is running the Calculator application, so all we need to do is to make sure that AboutPanel.nib sets the outlet when it is loaded.

  1. Click the Instances tab in the AboutPanel.nib (not MainMenu.nib) window to see the three objects for this nib.

  2. Inform IB that the File’s Owner in AboutPanel.nib will be of the Controller class. Do this by clicking the File’s Owner icon in the AboutPanel.nib window and then selecting Controller in the File’s Owner Info dialog, as shown in Figure 6-16. (If the Info dialog isn’t visible, type Command-1).

Changing the class type of the File’s Owner in AboutPanel.nib

Figure 6-16. Changing the class type of the File’s Owner in AboutPanel.nib

  1. Make the aboutPanel outlet in the File’s Owner point to the About box. Do this by first Control-dragging from the File’s Owner icon in the AboutPanel.nib (not MainMenu.nib) window to the (About) Panel icon in the same window. Finish the job by double-clicking the aboutPanel outlet in the File’s Owner Info dialog. See Figure 6-17.

Setting the aboutPanel outlet to point to the About box

Figure 6-17. Setting the aboutPanel outlet to point to the About box

When AboutPanel.nib is loaded, it will create the About box. The last step we completed arranged for the aboutPanel outlet in the File’s Owner object (i.e., the Controller object that loads AboutPanel.nib) to be set to the id of this newly created About box (represented by the Panel icon in AboutPanel.nib).

You might still be wondering about the File’s Owner. Recall the following Objective-C statement in the Controller’s showAboutPanel: method; when the program runs, this statement loads AboutPanel.nib:

[NSBundle loadNibNamed:@"AboutPanel.nib" owner:self]

The File’s Owner is the object that is specified by the self in the clause owner:self . In this case, the owner is the Controller instance (self ) that sends the above message to NSBundle. Thus, the aboutPanel outlet in the Controller instance is set to the id of the About box that is loaded.

The File’s Owner icon is called a proxy object because it is not a real object; instead, it is a proxy for a real object that was instantiated when another nib was loaded (in this case, that nib is MainMenu.nib). Setting File’s Owner outlets and sending messages to a File’s Owner object are the easiest ways to communicate between nibs.

Now, let’s run the Calculator application and see how it works:

  1. Activate PB and click the build and run button for the Calculator target. Save all files before building.

  2. With Calculator running, choose Calculator About Calculator.

The first time you choose the Calculator’s Calculator About Calculator menu command, you may notice a slight delay before the About box appears (and you may hear your hard drive reading the nib file). This delay is the time that it takes to load the nib file AboutPanel.nib into memory. However, if you close the About box and then choose Calculator About Calculator again, the About box should appear immediately because it’s being read from memory, not from disk.

  1. Choose Calculator Quit Calculator.



[13] Note that Objective-C initializes only instance variables. Variables that are static or local to a method are still uninitialized, just as in standard ANSI C.

[14] NSLog( ) works a lot like printf, except that the first argument is an NSString and the result is sent to the system console.

[15] It’s possible that the names of the text icons will change in later releases. Palettes may change too.

[16] The File’s Owner icon is actually a proxy for the object id that is passed to the method that loads the nib into memory.

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

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