CUSTOM CLASSES Interface Builder would only be mildly useful if all it could do was create, confi gure, and connect instances of the predefi ned framework objects found in the library p
Trang 1When 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
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 defi ne 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, confi gure, and connect instances of the predefi ned framework objects found in the library palette The power of Interface Builder explodes when you can defi ne your own classes, outlets, and actions, and then use Interface Builder to create instances of your custom objects, confi gure 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
Defi ne outlets in your custom classes that will be recognized by Interface Builder
Defi ne 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 defi nitions and incorporate that into the document It does this quickly, quietly, and transparently in the background All you have to do is defi ne your class By the time you ’ ve saved your class fi les and switched to Interface Builder, your class defi nitions will have been assimilated and are ready to instantiate, confi gure, and connect
➤
➤
➤
Download at getcoolebook.com
Trang 2Save your source fi les! Interface Builder only considers class defi nition
fi les that have been saved to disk Get into the habit of saving all fi les (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 defi nitions If a class or property doesn’t appear in Interface Builder, make sure your source fi les 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 defi ned in your project to a nib document.
To create an instance of a class, follow these steps:
1. Defi ne the class in Xcode
2. Save the interface fi le(s) that defi ne the class
3. In Interface Builder, fi nd 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 specifi c class (such as MyObject)
Figure 13 - 39 shows the class of a generic
NSObject being changed to MyAppDelegate,
a custom class defi ned in the active Xcode
project
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 specifi c
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 defi ned by its superclasses (NSTokenField, NSTextField,
NSControl, and NSView), in addition to any outlets and action methods that your subclass defi nes
FIGURE 13-39
Trang 3The 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:
Create an (External) Object when you subclass NSObject directly, or subclass any class that isn ’ t represented in the library palette
Anything means anything Interface Builder will let you change the class of
a generic NSObject instance to any class that exists, even ones defi ned 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 defi ne 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 modifi er in the property ’ s type
➤
➤
➤
➤
Download at getcoolebook.com
Trang 4All 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
If you ’ re using Objective - C 2.0, the preferred place to declare a property as an IBOutlet is in the
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
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 fi nd and rename any nib document references as well.
Adding Custom Actions to Your Class
Creating actions is about as simple as creating outlets:
1. Defi ne a method that conforms to the prototype (void) anyMethod :(id) sender
a. The method must have a void return type
b. The method should expect a single object reference as its only parameter
Trang 52. Replace the return type in the declaration with IBAction , as in
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 confi gured to send MyAppDelegate a - closeAboutWindow: message when the user clicked the button
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 fi t Many action methods simply ignore the sender parameter
Initializing Custom Objects at Run Time
For the most part, nib fi les contain archived (serialized) versions of Cocoa objects, but the nib
fi le loading mechanism makes some concessions, and relaxes a few of the normal rules of object archiving in order to make the nib fi le content as fl exible and convenient as possible Specifi cally:
Custom objects in a nib fi le 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 fi le It also means that any object that can be validly constructed with
➤
➤
Download at getcoolebook.com
Trang 6The following table describes exactly how objects in a nib document are constructed at run time:
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
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 fi le
The objects defi ned 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 fi le 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