3
@node Advanced Messaging
4
@chapter Advanced Messaging
5
@cindex advanced messaging
6
@cindex messaging, advanced techniques
8
Objective-C provides some additional possibilities for message routing besides
9
the capabilities described so far (inheritance and categories). One of the
10
most important is that it is possible for an object, upon receiving a message
11
it has not been set up to respond to, to @i{forward} that message to another
12
object. A second important capability, which forwarding relies on, is the
13
ability to represent method implementations directly in code. This supports
14
various reflective operations as well as optimization where messages are sent
18
@section How Messaging Works
19
Sending an Objective-C message requires three types of information:
23
The message @b{receiver} - the object which is to perform the request.
26
The message @b{selector} - this identifies the message, and is used to
27
locate the excecutable code of the corresponding @b{method} by searching the
28
structure of the class, and if necessary its superclasses, for an
32
The message @b{arguments} - once the implementation has been found, these are
33
simply passed to the method on the stack as in an ordinary function call.
36
In the message '@code{[taskArray insertObject: anObj atIndex: i]}', the
37
receiver is ``@code{taskArray}'', the selector is
38
``@code{insertObject:atIndex:}'', and the arguments are ``@code{anObj}'' and
39
``@code{i}''. Notice that the selector includes the argument titles and both
40
colons, but not the argument names. In other words, this method might have
41
been declared as '@code{- (void) insertObject: (id)anObject atIndex:
42
(unsigned)index;}', but the ``@code{anObject}'' and ``@code{index}'' are just
43
used for tracking the arguments within the method implementation code and not
44
for looking up the method itself.
46
The following sequence of events would occur on sending this message at
51
The internal @code{isa} pointer of the @b{receiver} (@code{taskArray}) is used
55
The class representation is searched for a method implementation matching the
56
@b{selector} (@code{insertObject:atIndex:}). If it is not found, the class's
57
superclass is searched, and recursively its superclass, until an
58
implementation is found.
61
The implementation is called, as if it were a C function, using the
62
@b{arguments} given (@code{anObj} and @code{i}), and the result is returned to
63
the code sending the message.
66
In fact, when the method implementation is actually called, it additionally
67
receives two @i{implicit} arguments: the @b{receiver} and the @b{selector}.
68
These additional hidden arguments may be referred to in the source code by the
69
names @code{self} and @code{_cmd}.
71
The process of looking up the method implementation in the receiver at runtime
72
is known as dynamic binding. This is part of what makes the language powerful
73
and flexible, but it is inevitably (despite clever caching strategies used in
74
the runtime library) a little slower than a simple function call in C. There
75
are, however, ways of short-circuiting the process in cases where performance
76
is at a premium. Before discussing this, we must first cover the concepts of
77
selectors and implementations in greater detail.
82
So far we have been using the following syntax to send messages to objects:
85
[myArray removeObjectIdenticalTo: anObject];
88
The example sends the message named @code{removeObjectIdenticalTo:} to
89
@code{myArray} with the argument @code{anObject}.
91
An alternative method of writing this is the following:
94
SEL removalSelector = @@selector(removeObjectIdenticalTo:);
95
[myArray performSelector: removalSelector withObject: anObject];
98
Here, the first line obtains the desired method selector in the form of a
99
compiled representation (not the full ASCII name), and the second line sends
100
the message as before, but now in an explicit form. Since the message that is
101
sent is now effectively a variable set at runtime, this makes it possible to
102
support more flexible runtime functioning.
105
@subsection The Target-Action Paradigm
107
One conventional way of using selectors is called the @i{target-action}
108
paradigm, and provides a means for, among other things, binding elements of a
109
graphical user interface together at runtime.
111
The idea is that a given object may serve as a flexible signal sender if it
112
is given a receiver (the @i{target}) and a selector (the @i{action}) at
113
runtime. When the object is told to send the signal, it sends the selector
114
to the receiver. In some variations, the object passes itself as an
117
The code to implement this paradigm is simple -
121
if (target == nil || action == 0)
123
return nil; // Target or action not set ... do nothing
125
if ([target respondsToSelector: action] == NO)
127
return nil; // Target cannot deal with action ... do nothing
129
return [target performSelector: action withObject: self];
133
As an example, consider a graphical button widget that you wish to execute
134
some method in your application when pressed.
137
[button setTarget: bigMachine]
138
[button setAction: @@selector(startUp:)];
141
Here, @code{button} stores the given target and action in instance variables,
142
then when it is pressed, it internally calls a method like
143
@code{performAction} shown above, and sends the message ``@code{[bigMachine
146
If you are used to programming with events and listeners in Java, the
147
target-action paradigm provides a lighter-weight alternative for the most
148
common case where only one object needs to be informed when an event occurs.
149
Rather than writing or extending a special-purpose adaptor class, you just
150
register the method you want called directly with the actuating element. If
151
you need to send the event to multiple objects, however, you would need to
152
write a special method to multiplex the event out. This would be
153
approximately comparable effort to what is always required in Java, and is
154
only needed in the minority of cases.
157
@subsection Obtaining Selectors
159
In addition to using the compile-time @code{@@selector} operator, there are a
160
couple of other ways of obtaining selectors.
164
In a method implementation, you can always obtain the current selector from
165
the variable @code{_cmd}:
167
- (void) removeObjectIdenticalTo: (id)anObject
169
SEL mySelector = _cmd;
175
At any point, you can use the @code{NSSelectorFromString()} function -
177
SEL mySelector = NSSelectorFromString(@@"removeObjectIdenticalTo:");
180
In reality, you would never use @code{NSSelectorFromString} for a constant
181
string as shown; @code{@@selector} would do and is more efficient, since is a
182
compile-time operator. Its chief utility lies in the case where the selector
183
name is in a variable value (for whatever reason).
187
If you ever need to test the contents of a @code{SEL} variable for equality
188
with another, you should use the function @code{sel_eq()} provided as part of
189
the GNU Objective-C runtime library. This is necessary because, while the
190
compiler tries to ensure that compile-time generated references to selectors
191
for a particular message point to the same structure, selectors produced at
192
runtime, or in different compilation units, will be different and a simple
193
pointer equality test will not do.
196
@subsection Avoiding Messaging Errors when an Implementation is Not Found
198
Using @b{typed} objects as shown below, the compiler would forewarn
199
you if the @code{anObject} was unable to respond to the @code{alert:}
200
message, as it knows what type of object @code{anObject} is:
203
SomeClass *anObject; // an instance of the 'SomeClass' class
205
anObject = [[SomeClass alloc] init]; // build and initialize the object
206
[anObject alert: additionalObject]; // compiler warns if 'alert:' not
207
// defined in SomeClass or a superclass
210
However at times the compiler will not forewarn you that a message will
211
attempt to invoke a method that is not in the @b{receiver's} repertoire. For
212
instance, consider the code below where @code{anObject} is not known to
213
implement the @code{alert:} message:
216
id anObject; // arbitrary object;
218
anObject = [[SomeClass alloc] init]; // build and initialize object
219
[anObject alert: additionalObject]; // compiler cannot check whether
220
// 'alert' is defined
223
In this case, the compiler will not issue a warning, because it only knows
224
that @code{anObject} is of type @code{id} @dots{} so it doesn't know what
225
methods the object implements.
227
At runtime, if the Objective-C runtime library fails to find a @b{method
228
implementation} for the @code{alert:} message in the @code{SomeClass} class
229
or one of its superclasses, an exception is generated. This can be avoided
232
The first way is to check in advance whether the method is implemented:
235
if ([anObject respondsToSelector: @@selector(alert:)] == YES)
237
[anObject alert: additionalObject]; // send it a message.
241
// Do something else if the object can't be alerted
245
The second way is for the object the message was sent to to @i{forward} it
252
What actually happens when the GNU Objective-C runtime is unable to find a
253
method implementation associated with an object for a given selector is that
254
the runtime instead sends a special @code{forwardInvocation:} message to the
255
object. (Other Objective-C runtimes do the same, but with a slightly
256
different message name and structure.) The object is then able to use the
257
information provided to handle the message in some way, a common mechanism
258
being to forward the message to another object known as a @b{delegate}, so
259
that the other object can deal with it.
262
- (void) forwardInvocation: (NSInvocation*)invocation
264
if ([forwardee respondsToSelector: [invocation selector]])
265
return [invocation invokeWithTarget: forwardee];
267
return [self doesNotRecognizeSelector: [invocation selector]];
273
@b{@code{invocation}} is an instance of the special @code{NSInvocation} class
274
containing all the information about the original message sent, including its
275
@b{selector} and its arguments.
278
@b{@code{forwardee}} is an instance variable containing the @code{id} of an
279
object which has been determined to be likely to implement methods that this
283
The @b{@code{NSInvocation}} class has a convenience method that will pass the
284
message on to a target object given as argument.
287
The @b{@code{doesNotRecognizeSelector}} method is a fallback which is
288
implemented in @code{NSObject}. Unless it has been overidden, its behavior
289
is to raise a runtime exception (a @code{NSInvalidArgumentException} to be
290
exact), which generates an error message and aborts.
293
Forwarding is a powerful method for creating software patterns. One of these
294
is that forwarding can be used to in effect provide a form of multiple
295
inheritance. Note, however that, unlike inheritance, a forwarded method will
296
not show up in tests like @code{respondsToSelector} and
297
@code{isKindOfClass:}. This is because these methods search the inheritance
298
path, but ignore the forwarding path. (It is possible to override them
301
Another pattern you may come across is @i{surrogate object}: surrogates
302
forward messages to other objects that can be assumed to be more complex. The
303
@code{forwardInvocation:} method of the surrogate object receives a message
304
that is to be forwarded; it determines whether or not the receiver exists, and
305
if it does not, then it will attempt to create it. A @b{proxy} object is a
306
common example of a surrogate object. A proxy object is useful in a remote
307
invocation context, as well as certain scenarios where you want one object to
308
fulfill functions of another.
311
Need to talk about NSMethodSignature and methodSignatureForSelector?
314
@section Implementations
316
Recall that when a message is sent, the runtime system searches for a method
317
implementation associated with the recipient object for the specified
318
selector. (Behind the scenes this is carried out by a function
319
``@code{objc_msgSend()}''.) This may necessitate searches across multiple
320
superclass objects traversing upwards in the inheritance hierarchy, and takes
321
time. Once the runtime finds an implementation for a class, it will cache the
322
information, saving time on future calls. However, even just checking and
323
accessing the cache has a cost associated with it. In performance-critical
324
situations, you can avoid this by holding on to an implementation yourself.
325
In essence, implementations are function pointers, and the compiler provides a
326
datatype for storing them when found at runtime:
329
SEL getObjSelector = @@selector(getObjectAtIndex:);
330
// get the 'getObjectAtIndex' implementation for NSArray 'taskArray'
331
IMP getObjImp = [taskArray methodForSelector: getObjSelector];
332
// call the implementation as a function
333
id obj = (getObjImp)( taskArray, getObjSelector, i );
336
Here, we ask the runtime system to find the '@code{taskArray}' object's
337
implementation of '@code{getObjectAtIndex}'. The runtime system will use the
338
same algorithm as if you were performing a method call to look up this code,
339
and then returns a function pointer to it. In the next line, this pointer is
340
used to call the function in the usual C fashion. Notice that the signature
341
includes both the object and the selector -- recall that these are the two
342
implicit arguments, @code{self} and @code{_cmd}, that every method
343
implementation receives. The actual type definition for @code{IMP} allows
344
for a variable number of additional arguments, which are the explicit
345
arguments to the method call:
348
typedef id (*IMP)(id, SEL, ...);
351
The return type of @code{IMP} is @code{id}. However, not all methods return
352
@code{id}; for these others you can still get the implementation, but you
353
cannot use an @code{IMP} variable and instead must cast it yourself. For
354
example, here is such a cast for a method taking a double and returning
358
double (*squareFunc)( id, SEL, double );
361
squareFunc = (double (*)( id, SEL, double ))
362
[mathObj methodForSelector: @@selector(squareOf:)];
364
result = squareFunc(mathObj, @@selector(squareOf:), 4);
367
You need to declare such a function pointer type for any method that returns
368
something besides @code{id} or @code{int}. It is not necessary to declare the
369
argument list (@code{double}) as we did above; the first line could have been
370
``@code{double (*squareFunc)( id, SEL, @b{...} )}'' instead.
372
An excellent exposition of the amount of time saved in using
373
@code{methodForSelector} and other details of the innards of Objective-C and
374
the Foundation may be found here:
375
@url{http://www.mulle-kybernetik.com/artikel/Optimization/opti-3.html}.
377
You should realize that it is only worth it to acquire the @code{IMP} if you
378
are going to call it a large number of times, and if the code in the method
379
implementation itself is not large compared with the message send overhead.
380
In addition, you need to be careful not to call it when it might be the wrong
381
function. Even when you are sure of the class of the object you are calling
382
it on, Objective-C is sufficiently dynamic that the correct function could
383
change as a program runs. For example, a new category for a class could be
384
loaded, so that the implementation of a method changes. Similarly, a class
385
could be loaded that poses as another, or one that was posing stops doing so.
386
In general, @code{IMPs} should be acquired just before they are to be used,
387
then dropped afterwards.
390
@comment Making Forwarding Transparent