Printing arguments sent to forwardInvocation: subclass of NSProxy - iphone

I want to intercept messages sent to a proxy object by just printing the selector and arguments. Even if the proxy does not implement them and does not have a target object. Please help. I have looked at several options and Apple docs but they assume that you already know the target object. I want to do this cleanly without memory issues.
#implementation MyProxy
-(void)forwardInvocation:(NSInvocation*)anInvocation
{
// at this point I would
//like to fetch the arguments and put on an array
NSMutableArray *myArgs = .....;
NSLog(#"Invoking selector %#", theSelector);
NSLog (myArgs); // this should print me the list of arguments to the method
}
#end
// e.g
MyProxy *proxy = [[MyProxy alloc] init];
[proxy SendMeAnyThing: #"hello"]; // this should print me arguments
or [proxy add: 12 to: 89 sub: 89]; // should print the arguments
Thanks thanks

The arguments are of just about any C type, including Objective-C types, that may be passed to the method. Thus, they can't be represented in an array.
Note that invoking a method that is not declared anywhere doesn't make any sense. Quite specifically, the compiler has no idea how to encode the arguments at the call site to make a valid C function call (a method call is really just a C function call to objc_msgSend() or a variant). So, to answer your "any method, even if it doesn't exist" question; no, you can't do that.
You can, however, effectively eliminate all compiler warnings. If you eliminate all compiler warnings -- all "method foo:bar: has can't be found" type warnings -- then that means the compiler does have enough information and you can do whatever the heck you want with a proxy.
Furthermore (as I read more into your question), there is no need to implement any method on the proxy. A proxy can quite happily forward-into-NSInvocation any method call. Written correctly, you can have a proxy stand in for any object without issue.
What you need to do is enumerate the arguments using the API of NSInvocation, sussing out the types and then decoding each argument accordingly and printing appropriately.
You can grab the number of arguments by invoking numberOfArguments on the method signature of the NSInvocation instance (the signature can be had via the methodSignature method).
Then, loop through the arguments and call getArgumentTypeAtIndex: on the method signature to get the type. You would then most likely write a switch() statement on the type encoding to then call getArgument:atIndex: and decode appropriately based on type.
Note that argument 0 is self and argument 1 is _cmd; the SEL of the method that was invoked.

Related

strange behaviour of objective C

Actually I am from java background and I am learning objective c.I am very confused about strange behaviour of objective C."Please Read 3rd Question its important one."
Questions are provided in sequence so please give answers in sequence as its understandable to me and others.
Question 1
I have two classes derived from NSObject: A and B:
#interface A : NSObject
#end
#interface B : NSobject
-(void)display; // It displays "I am class B"
#end
Now if I do this:
A *a = [[B alloc]init]; // Show warning not error (it must be illegal)
[a display]; // prints "I am class B"
It calls the display method of class B. I don't think that it should happen because:
A doesn't have the method display. By polymorphism.
This could be a security threat as I am creating reference of any class and passing object of any another class and accessing data by it.
There could be design issues as Dog class instance gets an object of Printer class and now i am calling print method on Dog instance.
I have reference of NSArray and passed object of NSMutableArray and now i am calling NSMutableArray method on this instance.
[nsarr addObject:#:abc]; //Looking very odd
Question 2
If I have Foo protocol and if any class is not confirming it. It should not be allowed to get object of that class in protocol reference.
#protocol Foo
#required
-(void)abc;
#end
If i call:
id<Foo> obj= [[B alloc]init]; // Shows warning ignore it for now as it must be illegal also
[obj display]; // It will call display method which should be illegal
It should not happen, as B is not conforming to protocol Foo and obj is taking B object and calling B instance method. I think its very bad because of polymorphism and security
Question 3
If my class has a class method which returns an object of that class which is not autoreleased, the compiler shows warning. If I pass the object returned by that class (not conforming protocol) method to reference of protocol. (IT SHOULD BE AN ERROR).
id<Foo> obj = [Abc aClassMethodReturnsObjectWhichNotAutoreleased]; //show warning
It shows a warning which is good. Abc did not conform to the protocol Foo
BUT
id<Foo> obj = [NSArray arrayWithObjects:#"abc",#"def",nil]; // It does **not** show a warning as it will return autorelease object. NSArray doesn't conform protocol Foo
Why does the above assignment to the NSArray class not show a warning as it is showing in the previous example.
Thanks in advance.
EDIT
*Answer 3rd Question:*As NSArray returns id object which will allow to pass in "id obj" but in "aClassMethodReturnsObjectWhichNotAutoreleased" case the method returns "ABC *" pointer so that is why compiler giving warning in this case.
Question 1:
A *a = [[B alloc]init]; //Show warning not error (it must be illegal)
[a display]; //prints "I am class B"
Here you are using a static type A for the variable named a. You are then assigning a different type of object (B) to the variable.
Unlike java, Objective-C does not enforce the static typing requirement, however it does warn you when it is being compiled since the compiler detected a difference between the declared type and the actual type of the object. It happily stuffs the B object into your variable though, so a is now pointing to the B object that you created. Once the program is compiled and running (at run-time), A *a is treated the same as id a.
Another feature of Objective-C is that you can send any message to any object at any time. This is part of the dynamic nature of Objective-C. Obviously there are cases where sending the wrong message to an object can cause bad things (tm) to happen so you need to ensure that you only send appropriate messages. There are various functions that can test the class of an object at run-time, or even test to see if it is able to handle a particular message before you send it in order to prevent the bad things. If you are using static typing (like in this example) then the compiler will issue warnings to tell you that you may have made a mistake and should review the code.
Question 2:
This is actually very similar to question 1. The compiler is warning you that you are assigning what appears to be an incorrect value to the variable, however at run-time you can send any message to any object, so it will work on the actual object instead of the "expected" object from the type declaration.
Question 3:
Good question. I would have thought that you would get a warning there too. Maybe someone else can help out on that. My first thought is that this is a bug and should be reported as such, but there may be a reason for it that I'm not aware of....
Objective-C and Java have very different type rules, as you have discovered.
Java is strictly statically typed, which means that types must match, and you can never make an assignment that is not allowed by the type conversion rules.
Objective-C is dynamically typed with optional static types. You can break out of the type system at any time. For some cases, the compiler will emit warnings, but it is still allowed.
This is the reason why you are seeing the behavior. Objective-C is not broken, it just have different rules than the ones you know from Java.
Apple has a lot of documentation of the specific rules, perhaps you would want to read Enabling Static Behavior.
Here are some more resources about dynamic vs static typing for you:
Dynamic type languages versus static type languages and What do people find so appealing about dynamic languages?
A *a = [[B alloc]init]; //Show warning not error (it must be illegal)
[a display]; //prints "I am class B"
Because you initialized variable from B class that have display property.
It's correct

Responds to, but not known?

This is a slight follow on from a previous question:
for(id <stuffieProtocol> eachObject in stuffieArray) {
if([eachObject respondsToSelector:#selector(secretID)]) [eachObject secretID];
}
The above is a line from a fast enumeration loop that takes a number of objects out of an NSArray and checks to see if they respond to the method secretID. The method secretID is not part of the #protocol but rather a method defined on one of the objects in the collection.
The if statement above fails because the compiler says "No known instance method for selector secretID" Which is fine, id does not care and the method is not defined in <stuffieProtocol> I can fix this by casting each object to the type that does define secretID:
if([eachObject respondsToSelector:#selector(secretID)]) [(Ted *)eachObject secretID];
My question is in the original code, how does the compiler know that eachObject responds to the method secretID but yet when you ask it to call that method its says "No known method" I am just a little curious about the mechanics?
The compiler doesn't know anything about whether the object responds to that selector but the runtime does. (i.e. The compiler doesn't execute the code.) The compiler only cares that any NSObject can respond to respondsToSelector:.

Why is `&` (ampersand) put in front of some method parameters?

I'ver wondered, why is it that in front of an NSError, such as below, do we put: &error and not error?
E.g.
NSArray *result = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
Hope you can explain, also is this always the way or only in certain situations this is needed? Thanks.
You need to take the address of error because the function needs to modify it. error is passed by pointer, so you need the "take address" operator & for it.
C and Objective-C pass parameters by value. If you pass error without an ampersand and the method that you call modifies it, your function that made the call would not see any changes, because the method would operate on its local copy of NSError*.
You know that you need an ampersand in front of the corresponding parameter if you look at the signature of the method and see ** there:
- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error
// ^ one ^^ two
The error parameter's type is (NSError **), that is a pointer to a pointer to an NSError. The error variable that you use as the argument is probably declared as NSError *, so in order to get the types to match properly, you have to use the address of operator to get a pointer to a pointer (&error). The reason the method needs a pointer to a pointer in the first place is so that it can modify the value of error and have that new value be available to you, the caller of the method.
Essentially, the root of the issue is a hack for wanting to return a second (optional) object.
How can we do this, as we can only return one thing? Well, we could return some sort of (return_value, error) tuple, but that's a bit unwieldy. We can have as many parameters as we like though, can we do something with those...
So, methods/functions can't modify their parameters (to be precise, they operate with a copy, so any modifications they make are local). That is to say (concurrency issues aside) the value of fetchRequest before the message in your question will be equal to the value of fetchRequest afterwards. Note the object pointed to by fetchRequest might change, but the value of fetchRequest itself won't.
This puts us in a bit of a bind. Except, wait, we know we can happily take the value of a parameter and modify what it points to! If you look at the declaration for executeFetchRequest:error: you'll see it takes an NSError**. That's "a pointer to a pointer to an NSError". So, we can initialise an empty/dangling NSError*, find the address of it (with the unary & operator), and pass that in. The method can then assign to the NSError* pointed to by this.
Voila, we effectively have optional additional return values.

What is findTheAppropriateSelectorForTheCurrentSituation() and its content?

Referring to the discussion performSelector where is explained that with the following line it is possible to call a method
SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];
My question is what is the content of the method called: findTheAppropriateSelectorForTheCurrentSituation()?
//For me the most important question
And another question is, why I get the warnings when using this piece of code.
1.warning: implicit declaration of function 'findTheAppropriateSelectorForTheCurrentSituation'
2.warning: initialization makes pointer from integer without a cast
3."_findTheAppropriateSelectorForTheCurrentSituation", referenced from:
Thank you for your answeres in advance
You'd have to look up the documentation or disassemble the binary that contains that method in order to determine exactly what it does. As for your warning, your syntax is incorrect. You should use the #selector(name) syntax in order to create a selector you can use to call [obj performSelector:].

Can someone tell me the difference between the call in IOS

I have a method called Display. Can somebody explain me the difference of calling the same method in the following two ways.
[self Display];
[self performselector:#selector(Display)]
- (void)Display {
NSlog(#"Data");
}
both are basically the same with one minute difference.. #selector gives a name to your method which you can pass around as an attribute to other objects or in other function calls.
Like if you want to send a message to other object and you want to send display as an attribute then you will have to give it a name using #selector and thus you can send it.. its a pretty vague concept.. hope this helps.
and to quote apple documents...
"However, the performSelector: method allows you to send messages that
aren’t determined until runtime. A variable selector can be passed as
the argument:
SEL myMethod = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector:myMethod];
The aSelector argument should identify a method that takes no
arguments. For methods that return anything other than an object, use
NSInvocation."
[self Display] is shorter and easier to read, write and comprehend.
[self performSelector:#selector(Display)] makes it possible to execute arbitrary selectors. If you save the selector in a variable, then you can execute it later on without knowing the method you invoke. It is therefore more flexible. Even better: you can pass selectors and objects to other objects and let them invoke it for you when necessary. An example why you want to use this is the NSUndoManager which simple invokes a selector to undo an action if the user executes the Undo command.
I do not think that there is a big difference between examples you provided, but perform selector is very useful when you for instance wanna move execution of your method to the background thread.
[self Display]; is a call to a known method on a known object.
It's easy to give it some params if your want : [self DisplayWithParam1:(NSString*)aString param2:(int)aNumber param3:(NSDictionary*)aDict
[self performselector:#selector(Display)] is a call that allows you to call a possibly not known method on a possibly not known object type.
Let's imagine you have many kind of classes that all respond to a given protocol that require to have the Display method implemented. You put some objects of thoses different classes in an NSMutableArray. When parsing the array later, you will get id typed objects.
So calling[myArrayObject Display]; will work at runtime but will generate a warning at compile time as id does not support any method of course, even if you know that this object supports the method.
To prevent thoses warning, call [myArrayObject performselector:#selector(Display)];.
The problem with that call is that is harder to pass some parameters.
performSelector:withObject:withObject:
Sends a message to the receiver with two objects as arguments.
- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject
Parameters
aSelector
A selector identifying the message to send. If aSelector is NULL, an NSInvalidArgumentException is raised.
anObject
An object that is the first argument of the message.
anotherObject
An object that is the second argument of the message
Return Value
An object that is the result of the message.
Discussion
This method is the same as performSelector: except that you can supply two arguments for aSelector. aSelector should identify a method that can take two arguments of type id. For methods with other argument types and return values, use NSInvocation.
Availability
Available in Mac OS X v10.0 and later.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocSelectors.html
The #select call is faster. Generally the uglier (and less dynamic) the code you have in Objective-C, the faster it runs. Here, the selector call bypasses the usual call to objc_msgSend().
I wouldn't recommend writing code like this if you can avoid it. Selectors are somewhat common in Cocoa, but if you're using it for a speedup it's really not worth it. objc_msgSend() is highly optimized and very fast.