Can someone offer a concrete reason for using an NSInvocation instead of just using a Block, or even a regular method call? I am finding descriptions of NSInvocation around the Web, but no examples of where it is vital to use or even the only good option.
NSInvocations and blocks can both be used to encapsulate a method call, along with arguments and a receiver that aren't defined until runtime. Before blocks existed, NSInvocation was the only way to do this. If that's all you need to do, blocks are a better bet. Uses of NSInvocation are quite rare these days.
However, unlike blocks, which can represent any amount of code along with captured values, an NSInvocation always represents a single method call.
This has some advantages:
Unlike blocks, which are opaque, an NSInvocation can be queried for the selector, the receiver, the arguments and the signature of the invoked method. If you receive an NSInvocation as an argument to a method (as with NSObject's -forwardInvocation), you can extract the arguments and call a different method instead.
An NSInvocation can be constructed for an arbitrary method call at runtime using -initWithMethodSignature:. If you wanted to implement an eval() function for Objective-C, for example, you'd use NSInvocation to actually invoke the methods.
NSInvocation allows you to dynamically at runtime construct and invoke an Objective-C message call, to a method that you may not know at compile-time, and it allows you to set the arguments using the information about the types and number of arguments from the signature of the method which again you may not know at runtime. (You may have a place that needs to be able to call different methods with different signatures, and pass different things depending on those signatures.) Thus it adds a level of dynamic-ness to the message passing mechanism. I am not sure how blocks relate to this.
NSInvocation is also used in -forwardInvocation: if you want your object to be able to handle arbitrary (not fixed at compile-time) messages, where the message dispatch system constructs an NSInvocation object describing the call and pass it to you, so that you can introspect and potentially modify the arguments and invoke it on another object or otherwise handle the information. This adds a lot of dynamic-ness in handling of messages at runtime. I also don't know how blocks relate to this.
Related
I'm trying to understand the method "withArgs: executeMethod: " in smalltalk, squeak.
1. I am trying to understand what is the role of the method?
2. What arguments need to be passed to it for it to be carried out?
A good way to understand this method is by considering it as a syntactic variant of the general expression
object msg: arg (*)
where object is the receiver of the message with selector msg: and arg its argument. There are of course variants with no or multiple arguments, but the idea is the same.
When object receives this message (*) the Virtual Machine (VM) looks up for the CompiledMethod with selector msg: in the object's hierarchy, and transfers it the control, binding self to object and the formal argument of the method to arg.
Notice that this invocation is managed by the VM, no by the Virtual Image (VI). So, how could we reflect the same in the VI? Well, there are two steps in this behavior (1) find the method and (2) bind its formal receiver and arguments to the actual ones and let it run.
Step (1) is the so called lookup algorithm. It is easily implemented in Smalltalk: just ask the receiver its class, check whether the class includes the selector #msg: and, if not, go to the superclass and repeat. If all checks fail, issue the doesNotUnderstand: message.
Step (2) exactly requires what #withArgs:executeMethod: provides. It allows us to say
object withArgs: {arg} executeMethod: method
where method is the CompiledMethod found in step (1). [We have to use {arg} rather than arg because the plural in withArgs: suggests that the method expects an Array of arguments.]
Why would we want this?
Generally speaking, giving the VI the capability to mimic behavior implemented in the VM is good because it makes metaprogramming easier (and more natural).
More practically, a relevant example of the use of this capability is the implementation of Method Wrappers. Briefly described, given any particular method, you can wrap it (as the wrappee) inside a wrapper method, which also has a preBlock. If you then substitute the original method in the MethodDictionary where it belongs, with the wrapper, you can let the wrapper first execute the preBlock and then the intended method. The first task is easy: just send the message preBlock value. For the second we have the method (the wrappee), the receiver and the arguments (if any). So, to complete the task you only need to send to the receiver withArgs:executeMethod: with the actual argument(s) and the wrappee.
Ah! Let's not forget to mention that one of the reasons for having Method Wrappers is to measure testing coverage.
Note also that withArgs:executeMethod: does not require the second argument, i.e., the method to execute, to be in any class, let alone the class of the receiver. In particular, you could create a CompiledMethod on the fly and execute it on any given object. Of course, it is up to you to make sure that the execution will not crash the VM by, say, using the third ivar of the receiver if the receiver has only two etc. A simple way to create a CompiledMethod without installing it in any class is by asking the Smalltalk compiler to do so (look for senders of newCompiler to learn how to do that).
my question as the title says.obviously, the first parameter was used for this pointer , in some taste of c++.what about the second one? thak you.
The signature of objc_msgSend() is:
id objc_msgSend(id self, SEL op, ...);
Every method call is compiled down to a call to this function. I.e., if you call:
[anArray objectAtIndex:42];
That will be compiled as if it were:
objc_msgSend(anArray, #selector(objectAtIndex:), 42);
Now, to your question, why do methods get compiled down to a function that has the SEL as the second argument. Or, more specifically, why is this method:
- (id)objectAtIndex:(NSUInteger)index;
Exactly equivalent to this C function:
id object_at_index(id object, SEL _cmd, NSUInteger index);
The answer is speed speed speed.
Speed
Specifically, by doing this, then objc_msgSend() never has to rewrite the stack frame* and it can also use a tail call optimization to jump directly to the method invocation. This is the same reason why you never see objc_msgSend() in backtraces in the debugger (save for when you actually crash/break in the messenger).
objc_msgSend() uses the object and the _cmd to look up the implementation of the method and then, quite literally, jumps to that implementation.
Very fast. Stack frame untouched.
And, as others have stated, having _cmd around in the method implementation can be handy for a variety of reasons. As well, it also means that the messenger can do neat tricks like proxy support via NSInvocation and the like.
*rewriting the stack frame can be insanely complex and expensive. Some of the arguments might be in registers some of the time, etc... All architecture dependent ABI nastiness. One of the biggest challenges to writing things like imp_implementationWithBlock() was figuring out how to do so without touching the stack because doing so would have been too slow and too bloated to be viable.
The purpose of having the second parameter contain the selector is to enable a common dispatch mechanism. As such, the method dispatch code always expects the second parameter to be the selector, and dispatches based on that, or follows the inheritance chain up, or even creates an NSInvocation and calls forwardInvocation:.
Generally, only system-level routines use the selector argument, although it's rather nice to have it when you hit an exception or are in the debugger trying to figure out what routine is giving you difficulties if you are using forwardInvocation
From the documentation:
Discussion
This data type is a pointer to the start of the function that implements the method. This function uses standard C calling conventions as implemented for the current CPU architecture. The first argument is a pointer to self (that is, the memory for the particular instance of this class, or, for a class method, a pointer to the metaclass). The second argument is the method selector. The method arguments follow.
In Objective-C when you call a method you need to know the target, the selector and the eventual arguments. Let's suppose that you are trying to do this manually: how can you know which method to call if you don't know the selector? Do you call some random method? No, you call the right method because you know the method name.
I am trying to make a catch-all proxy that takes any selector with any type of arguments and sends an RPC call down the wire. In this case, the signature of the method is not known because it can be created arbitrarily by the end user.
I see that the method signature requires supplying type encodings for each of the arguments. Is there a type encoding that signifies absolutely anything (pointer, int, everything else)? Otherwise, is there another way to accomplish this effect?
"sort of", but not really... or, at least, not practically.
You can implement the method forwarding protocol such that unrecognized method calls will be wrapped up in an NSInvocation and then you could tear into the NSInvocation, but it really isn't practical for a number of reasons.
First, it only really works for relatively simple argument types. The C ABI is such that complex arguments -- structures, C++ objects, etc.. -- can be encoded on the stack in wonky ways. In fact, they can be encoded in ways where there isn't enough metadata to decode the frames.
Secondly, any kind of a system where "selectors can be created arbitrarily by the user" has a very distinct odor about it; an odor of "you are doing it the hard way". Objective-C, while exceptionally dynamic, was really not designed to support this level of pure meta-object pattern.
As well, any such resulting system is going to be exceptionally fragile. What if the "arbitrary selector" happens to be, say, #selector(hash)?
Can you describe in more detail about this catch-all proxy and what it needs to forward to?
If your proxy only needs to forward each message to one target, then it can do so in its -forwardingTargetForSelector: at runtime. If not (e.g. you need to forward to multiple targets or do other complicated manipulation), you need to implement -forwardInvocation: to handle it. Using -forwardInvocation: to handle calls requires you to implement -messageSignatureForSelector: because it needs to get the method signature in order to be able to create the invocation. (Even if you forward it to another object, that object also needs to either implement the method directly, add the method in response to +resolveInstanceMethod:, or handle it using -forwardInvocation:, all of which requires it to also have the signature.)
A method signature encodes the types of the arguments and return type. The reason that this information is needed for an invocation is that when these arguments are passed, they are laid out at compile-time (probably consecutively) in memory according to their types in the declaration. A large struct parameter is going to take up more space than an int parameter. A double is also probably bigger than an int. An invocation needs to store all of these arguments and let you access or change them by index. There is no way to figure out how the arguments are laid out at runtime unless you knew the types (or at least the sizes of the types).
Also, the message passing mechanism is different for methods that return structs (they call objc_msgSend_stret) from other methods (they call objc_msgSend) (and on some platforms, methods that return doubles use objc_msgSend_fpret). In the former case, the struct is not returned directly, but the location to write to is passed as an extra pointer argument as an out parameter. So knowing the return type is also critical to handling the call and the return value in the invocation.
Even if you are forwarding the invocation to some other object, ultimately that object (or some object it forwards to down the line) has to know the method signature somehow. So why not ask that object for the signature of the selector when you need it?
There is no "safe" signature that will work for all things, because different types have different sizes.
In Objective-C, when I want to call a subroutine, I send a message to an object, like:
[self mySubroutine:myParameter];
There is a (negligible?) performance penalty, so I could just use a C-style function call:
mySubroutine(myParameter);
The implementation of the latter would then reside outside the class’s #implementation context.
Is this a no-no? Is it common? Is there a best-practice on this?
Note that those are not necessarily equivalent. Since -mySubroutine is an instance method, it probably needs to access a given instance. In that case, your mySubroutine() function should have another parameter for the instance, too.
In general, use a method. If you’re worried about performance,1 you can always get an IMP to the method and use it as a function instead of the standard Objective-C message dispatch infrastructure.
That said, some disadvantages of using functions:
They cannot be overridden by subclasses;
There’s no introspection (when using the runtime to obtain a list of methods declared by an Objective-C class, functions aren’t enumerated);
They cannot be used as accessors/mutators of declared properties;
They aren’t visible to Key-Value Coding;
They cannot be directly used for Objective-C message forwarding;
They cannot be directly used in the various cases where a Cocoa API expects a selector (e.g. when using NSTimer).
Some advantages of using functions:
They cannot be overridden by subclasses (if you want to prevent this);
There’s no introspection (if you want to prevent this);
They can be inlined;
They can have file scope (static), preventing code from other files from accessing them.
1When you’ve determined that the message dispatch infrastructure is actually a bottleneck. This does happen; for instance, some Apple audio examples do not use Objective-C for audio processing.
Edit: Based on OP’s comment, another advantage of functions is that they aren’t necessarily related to a class. If the computation of an approximate value for the sine of an angle doesn’t depend on an Objective-C instance, there’s no need to make it a method — a function is a better fit.
It might be worth using where you have static utility functions, such as in a maths library.
In general though, if you need methods that act on the state of an object, the C approach won't be much use, as you won't have implicit access to self, unless you explicitly pass it as a parameter.
You may also run into namespace issues. With the Objective-C different classes can share method names, with the c approach all your functions will need different signatures.
Personally I would always use objective-c methods, the performance difference will be negligible.
I have a class which uses resolveInstanceMethod to dynamically implement methods.
When I call the dynamically implemented methods from other parts of the code, the compiler emits a warning that the object may not respond to the selector. I would like the compiler to not emit such warnings for this class, but I don't want to suppress warnings when I invoke an invalid selector on other classes. Is this possible?
Assuming you know the method signatures that will be dynamically resolved at compile time, you can declare 'em in an informal category:
#interface MyDynamicallyResolvingClass(MethodsThatWillResolveAtRuntime)
... declare the methods here ...
#end
No need to provide an implementation.
If you don't know the signatures -- if the method names are dynamic, too -- then you'll need to use either -performSelector: (or the single or double object argument variants) or you will likely want to use NSInvocation, unless performance is a major concern (if it is, there are alternative solutions that are significantly more fiddly).
Use performSelector:
It's equivalent to sending a message directly to the receiver, however, it allows you to send messages that aren’t determined until runtime.
If your methods take one or two arguments, you can use the sisters of this method: – performSelector:withObject: and – performSelector:withObject:withObject:
If your methods have more than two arguments, or arguments that are not of object type, this answer is not adapted.