According to Apple's NSInvocation class reference:
An NSInvocation
is an Objective-C message rendered static, that is, it is an action turned into an object.
And, in a little more detail:
The concept of messages is central to the objective-c philosophy. Any time you call a method, or access a variable of some object, you are sending it a message. NSInvocation
comes in handy when you want to send a message to an object at a different point in time, or send the same message several times. NSInvocation
allows you to describe the message you are going to send, and then invoke it (actually send it to the target object) later on.
For example, let's say you want to add a string to an array. You would normally send the addObject:
message as follows:
[myArray addObject:myString];
Now, let's say you want to use NSInvocation
to send this message at some other point in time:
First, you would prepare an NSInvocation
object for use with NSMutableArray
's addObject:
selector:
NSMethodSignature * mySignature = [NSMutableArray
instanceMethodSignatureForSelector:@selector(addObject:)];
NSInvocation * myInvocation = [NSInvocation
invocationWithMethodSignature:mySignature];
Next, you would specify which object to send the message to:
[myInvocation setTarget:myArray];
Specify the message you wish to send to that object:
[myInvocation setSelector:@selector(addObject:)];
And fill in any arguments for that method:
[myInvocation setArgument:&myString atIndex:2];
Note that object arguments must be passed by pointer. Thank you to Ryan McCuaig for pointing that out, and please see Apple's documentation for more details.
At this point, myInvocation
is a complete object, describing a message that can be sent. To actually send the message, you would call:
[myInvocation invoke];
This final step will cause the message to be sent, essentially executing [myArray addObject:myString];
.
Think of it like sending an email. You open up a new email (NSInvocation
object), fill in the address of the person (object) who you want to send it to, type in a message for the recipient (specify a selector
and arguments), and then click "send" (call invoke
).
See Using NSInvocation for more information.
See Using NSInvocation if the above is not working.
NSUndoManager
uses NSInvocation
objects so that it can reverse commands. Essentially, what you are doing is creating an NSInvocation
object to say: "Hey, if you want to undo what I just did, send this message to that object, with these arguments". You give the NSInvocation
object to the NSUndoManager
, and it adds that object to an array of undoable actions. If the user calls "Undo", NSUndoManager
simply looks up the most recent action in the array, and invokes the stored NSInvocation
object to perform the necessary action.
See Registering Undo Operations for more details.
If you see this warning:
warning: receiver 'MyCoolClass' is a forward class and corresponding @interface may not exist
you need to #import
the file, but you can do that in your implementation file (.m), and use the @class
declaration in your header file.
@class
does not (usually) remove the need to #import
files, it just moves the requirement down closer to where the information is useful.
For Example
If you say @class MyCoolClass
, the compiler knows that it may see something like:
MyCoolClass *myObject;
It doesn't have to worry about anything other than MyCoolClass
is a valid class, and it should reserve room for a pointer to it (really, just a pointer). Thus, in your header, @class
suffices 90% of the time.
However, if you ever need to create or access myObject
's members, you'll need to let the compiler know what those methods are. At this point (presumably in your implementation file), you'll need to #import "MyCoolClass.h"
, to tell the compiler additional information beyond just "this is a class".
Best Solution
Class methods, just like instance methods, should adhere to the standard Cocoa memory management rules.
Presumably they are returning an autoreleased object, or a reference to a singleton or something like that. Either way, you need not release the object unless it started with "alloc" or "new" or contained "copy". You need not retain it unless you're looking to keep it around past the scope of the current autorelease pool, by storing it in an iVar or something like that.