天天看點

Cocoa程式設計之IBAction和IBOutlet含義 IBAction / IBOutlet / IBOutletCollection

development process as a whole, insofar as what they can tell other developers about the code itself. 

For developers just starting with Cocoa &amp; Cocoa Touch, the  <code>IBAction</code> , <code>IBOutlet</code> ,

and  <code>IBOutletCollection</code> macros

are particularly bewildering examples of this phenomenon. As we'll learn in this week's article, though having outgrown their technical necessity, they remain a vibrant tradition in the culture of Objective-C development. 

Unlike othertwo-letter prefixes,  <code>IB</code> does

not refer to a system framework, but rather Interface Builder. 

1988). Before it was subsumed into Xcode 4, Interface Builder remained remarkably unchanged from its 1.0 release. An iOS developer today would feel right at home on a NeXTSTEP workstation, control-dragging views into outlets. 

Back when they were separate applications, it was a challenge to keep the object graph represented in a  <code>.nib</code> document

in Interface Builder synchronized with its corresponding  <code>.h</code> &amp;  <code>.m</code> files

used as keywords, to denote what parts of the code should be visible to Interface Builder. 

<code>IBAction</code> and  <code>IBOutlet</code> are,

themselves, computationally meaningless, as their macro definitions (in  <code>UINibDeclarations.h</code> )

demonstrate: 

attributes: 

As early as 2004 (and perhaps earlier),  <code>IBAction</code> was

no longer necessary for a method to be noticed by Interface Builder. Any method with a signature <code>- (void){name}:(id)sender</code> would be visible in the outlets pane. 

Nevertheless, many developers find it useful to still use the  <code>IBAction</code> return

type in method declarations to denote that a particular method is connected to an outlet. Even for projects  not using Storyboards / XIBs may choose to employ <code>IBAction</code> to

Thanks to strong, and often compiler-enforced conventions, naming is especially important in Objective-C, so the question of how to name IBAction methods is one not taken lightly. Though there is some disagreement, the preferred convention is as follows:

Return type of  <code>IBAction</code> . 

Method name of an active verb, describing the specific action performed.Method names like  <code>didTapButton:</code> or  <code>didPerformAction:</code> sound

more like things a  <code>delegate</code> might

be sent. 

Required  <code>sender</code> parameter

of type  <code>id</code> .  All

target / action methods will pass the  <code>sender</code> of

the action (usually the responder) to methods that take a parameter. If omitted in the method signature, things will still work. 

Optional event parameter of type  <code>UIEvent *</code> , named  <code>withEvent:</code>(iOS

only) . In UIKit, a second  <code>UIEvent *</code> parameter, corresponding to the touch, motion, or remote control event triggering the responder, will be passed to target / action methods accepting this second parameter. The convention is to use  <code>withEvent:</code> in

the method signature, to match the  <code>UIResponder</code> APIs. 

For example:

Unlike  <code>IBAction</code> ,  <code>IBOutlet</code> is

still required for hooking up properties in code with objects in a Storyboard or XIB. 

An  <code>IBOutlet</code> connection is usually

established between a view or control and its managing view controller (this is often done in addition to any  <code>IBAction</code> s

that a view controller might be targeted to perform by a responder). However, an <code>IBOutlet</code> can

also be used to expose a top-level property, like another controller or a property that could then be accessed by a referencing view controller. 

As with anything in modern Objective-C,  properties are preferred to direct ivar access . The same is true of  <code>IBOutlet</code> s: 

an instance variable. However, since properties are the conventional way to expose and access members of a class, both externally and internally, they are preferred in this case as well, if only for consistency. 

One unfortunate consequence (if you want to call it that) of ARC is the ambiguity of when a  <code>IBOutlet</code> <code>@property</code> should

be declared as  <code>weak</code> or  <code>strong</code> .

The ambiguity arises from the fact that most outlets have no discernible behavioral differences between  <code>weak</code> or  <code>strong</code> —it

just works. 

...except when it doesn't... and things crash, or the compiler warns about  <code>weak</code>or  <code>strong</code> use. 

So what should one do?  Always declare  <code>IBOutlet</code> properties

as  <code>weak</code> , except when they

need to be  <code>strong</code> ,

Outlets should be changed to  <code>strong</code> when

the outlet should be considered to own the referenced object: 

This is often the case with File’s Owner—top level objects in a nib file are frequently considered to be owned by the  <code>File’s Owner</code> . 

You may in some situations need an object from a nib file to exist outside of its original container. For example, you might have an outlet for a view that can be temporarily removed from its initial view

hierarchy and must therefore be maintained independently.

The reason why most  <code>IBOutlet</code> views

can get away with  <code>weak</code> ownership

is that they are already owned within their respective view hierarchy, by their superview. This chain of ownership eventually works its way up to the  <code>view</code> owned

by the view controller itself. Spurious use of  <code>strong</code> ownership

on a view outlet has the potential to create a retain cycle. 

<code>IBOutlet</code> 's obscure step-cousin-in-law-once-removed

is <code>IBOutletCollection</code> . Introduced

in iOS 4, this pseudo-keyword allows collections of  <code>IBOutlet</code> s

to be defined in Interface Builder, by dragging connections to its collection members. 

<code>IBOutletCollection</code> is  <code>#define</code> 'd

in  <code>UINibDeclarations.h</code> as: 

Unlike  <code>IBAction</code> or  <code>IBOutlet</code> ,  <code>IBOutletCollection</code> takes

As a top-level object, an  <code>IBOutletCollection</code> <code>@property</code> should

be declared  <code>strong</code> , with an  <code>NSArray *</code> type: 

There are two rather curious things to note about an  <code>IBOutletCollection</code>array: 

Its order is not necessarily guaranteed . The order of an outlet collection appears to be roughly the order in which their connections are established in Interface Builder. However, there

are numerous reports of that order changing across versions of Xcode, or as a natural consequence of version control. Nonetheless, having code rely on a fixed order is strongly discouraged. 

No matter what type is declared for the property, an <code>IBOutletCollection</code> is

always an  <code>NSArray</code> .

In fact, any type can be declared:  <code>NSSet *</code> ,  <code>id &lt;NSFastEnumeration&gt;</code> —heck,

even  <code>UIColor *</code>! No matter what

you put, an  <code>IBOutletCollection</code> will

always be stored as an  <code>NSArray</code> ,

so you might as well have that type match up in your declaration to avoid compiler warnings. 

With the advent of Objective-Cobject literals,  <code>IBOutletCollection</code> has

fallen slightly out of favor—at least for the common use case of convenience accessors, as in: 

Since declaring a collection of outlets is now as easy as comma-delimiting them within  <code>@[]</code> ,

it may make just as much sense to do that as create a distinct collection. 

Where  <code>IBOutletCollection</code> really

shines is how it allows for multiple to define a unique collection of outlets under a shared identifier. Another advantage over a code-defined  <code>NSArray</code> literal

is that a collection can contain outlets that themselves are not connected to  <code>File's Owner</code> . 

The next time you're managing a significant or variable number of outlets in an iOS view, take a look at  <code>IBOutletCollection</code> . 

<code>IBAction</code> ,  <code>IBOutlet</code> ,

and  <code>IBOutletCollection</code> play

important roles in development, on both the compiler level and human level . As Objective-C continues to rapidly evolve as a platform, it is likely that they may someday be as completely vestigial as the wings of flightless birds or eyes of cavefish. For now,

though, it's important to understand what they are, and how to use them, if you plan on creating apps in any capacity.

繼續閱讀