Executing code defined in a string - ios

I would like to be able to execute a piece of code that is defined in a string. I am aware of performSelector: but the object that will perform the selector is going to be different.
Example strings
[[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] hasFlash]
[UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]
So what I would like to do is something along the lines of
SEL selector = NSSelectorFromString(#"[[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] hasFlash]");
if (selector) {
// Show flash buttons
}

You can not fire a selector that calls a nested method call.
Selectors are only method names with showing number of arguments as method:abc:yxa:
As the statement below:
SEL selector = NSSelectorFromString(#"[[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] hasFlash]");
is calling
[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]
then
[objectReturnedByAbove hasFlash]

Related

Selector in Method over riding

In the case of method over riding in objective c how selector knows that which method needs to call via selector?
As we dont pass any arguments in slector section...
Ex:
in tmp.m file
There is 2 methods with different arguments
-(void)details
{
}
-(void)details:(NSDictionary *)result
{
}
And when m call another method with the use of selector as:
[mc detailstrac:[[NSUserDefaults standardUserDefaults] valueForKey:#"userID"] tracid:self.trac_id selector:#selector(details:)];
How selector knows to call which method !
I have checked that
-(void)details:(NSDictionary *)result
{
}
this method is called every time then what about
-(void)details
{
}
this ?
Selector will know on the basis how you call the method like from your example,
[mc detailstrac:[[NSUserDefaults standardUserDefaults] valueForKey:#"userID"] tracid:self.trac_id selector:#selector(details:)];
when you call #selector(details:) then the selector will call this method
-(void)details:(NSDictionary *)result { }
And When you call #selector(details) then the selector will call
-(void)details { }
The main difference here is #selector(details) and #selector(details:).
Hope you understand my point!
Happy Coding!

What happens when a parametrized selector is called with no parameters?

I was going over this example in which a selector is used. I have copied the code from there for convenience.
// MYTapGestureRecognizer.h
#interface MYTapGestureRecognizer : UITapGestureRecognizer
#property (nonatomic, strong) NSString *data;
#end
// MYTapGestureRecognizer.m
#implementation MYTapGestureRecognizer
#end
// =====================
....
MYTapGestureRecognizer *singleTap = [[MYTapGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected:)];
singleTap.data = #"Hello";
.....
// ====================
-(void)tapDetected:(UITapGestureRecognizer *)tapRecognizer {
MYTapGestureRecognizer *tap = (MYTapGestureRecognizer *)tapRecognizer;
NSLog(#"data : %#", tap.data);
}
My question is
1-When self calls the selector what parameter does it pass in the above case ?
2- Also if a selector (pointing to a method that requires parameters) is called (see example below) and no parameters are passed are there any defaults in that case ? If possible is there any documentation for that ?
Suppose the signature of MyTest is
- (void) MyTest : (NSString*) a;
Now constructing and calling a selector
SEL a = NSSelectorFromString(#"MyTest:");
[t performSelector:a]; //Works Fine and the call is made - However Notice no parameter is passed . In this case what would the value of the parameter be in the method ?
I checked the following but I could not find this information
Apple docs
Rys Tutorials
Answers to your questions:-
When self calls the selector what parameter does it pass in the above case ?
If a tap is detected and the selector is called, the parameter will be an object of UITapGestureRecognizer. This will be the same instance on which the tap gesture is detected.
Also if a selector (pointing to a method that requires parameters) is called (see example below) and no parameters are passed are there any defaults in that case ? If possible is there any documentation for that ?
Why do you want to call the method like that, is there any special purpose?. If not, you can call the method just like
[self tapDetected:nil];
or
[self performSelector:#selector(tapDetected:) withObject:nil];
If you call the method as provided in the question, most probably it will crash.
If you wish to call the method on self, pass nil parameter to it. But i do not understand what purpose is it serving you.
Also if you do not send parameters to your methods, it is going to fail at your builds. You have to pass either the parameter or nil.
Also if your method does not accept nil parameters it might cause an exception - 'NSInvalidArgumentException'
Normally if you want to access that selector via self, use it like :
[self tapDetected:nil];
You need to handle this case in your selector, like :
-(void)tapDetected:(UITapGestureRecognizer *)tapRecognizer {
if (tapRecognizer)
{
MYTapGestureRecognizer *tap = (MYTapGestureRecognizer *)tapRecognizer;
NSLog(#"data : %#", tap.data);
}
else
{
//Do your work
}
}
Also not only this, if you are not sure of parameter you are passing change your selector decalartion as id, like :
-(void)tapDetected:(id)sender {
NSString *className = NSStringFromClass([id class]);
NSLog(#"Object passed is of class : %#", className);
//And make check here
if ([id isKindOfClass:[MYTapGestureRecognizer class]])
{
//Do your work here
}
}
There are no default cases, you need to handle every case manually or else app will crash.
SEL a = NSSelectorFromString(#"MyTest:");
[t performSelector:a]; //Works Fine and the call is made - However Notice no parameter is passed . In this case what would the value of the parameter be in the method ?
It will be undefined junk. You have no guarantees about what it might contain. Most likely, it will be an invalid pointer. If you're unlucky, it might be a valid pointer to some arbitrary object and operating on it will corrupt your app's state. If you're lucky, it will crash so you can find the problem.

Is it possible to get arguments from selector variable?

Is it possible to get the argument from the selector varibale.
For Example
-(void)methodTest:(NSString*)someArg{
SEL selector = #selector(methodTest:);
[self testCall:selector];
}
-(void)testCall:(SEL)selectorArg{
//I would like to get the parameter from the selector (selectorArg)
}
My Questions:
1. Does the selector has the argument, someArg? If not, how to create the selector variable with argument.
2. What is the other way around to do the same?
Just curious to know.
If you create a selector like:
SEL selector = #selector(methodTest:);
It means (Note the :) that the selector expects an argument.
You can pass argument to such method like:
[self performSelector:selector withObject:argument afterDelay:0.0];
And the method syntax will be:
- (void)methodTest:(id)someArgument;
If the selector is created by the following syntax:
SEL selector = #selector(methodTest);
Then you can't pass any argument to this selector.
You can call like:
[self performSelector:selector withObject:nil afterDelay:0.0];
And the method syntax will be:
- (void)methodTest;
I'm not totally understand what you searching for, but I'm guessing you need
performSelector method. Please check this SO thread: iOS - How to implement a performSelector with multiple arguments and with afterDelay?

How XCode knows about name of function at compile time?

I have written simple code to practice selector in Objective C, which is working fine
NSMutableArray *array = [NSMutableArray arrayWithObjects:#"A",#"B", nil];
NSLog(#"Before adding %#",array);
SEL message = #selector(addObject:); //I will change this line
if([array respondsToSelector:message])
{
[array performSelector:message withObject:#"C"];
}
NSLog(#"After adding %#",array);
But as soon as I change selector line to,
SEL message = #selector(addobject:);// Just changed name of selector
XCode starts giving warning :
Undeclared selector 'addobject:'
Now, question is how XCode knows at compile time about name of method is correct or not. Is there always list of selector generates internally for whatever object I am creating? In this case for NSMutableArray
All Xcode knows is that there is no class, either in the system code or in your program, that declares a selector called addobject. You can prove this by creating a custom class that declares an addobject method, and the warning should go away, but of course the program will crash with a unrecognized selector sent to object error message.

issue with a selector

I'm running into problems with a selector. I'm trying to dynamically name an array, winnerArray1, winnerArray2, winnerArray3, etc.
The variable someVariable is in a loop that increases so that will get incremented.
I get unrecognized selector sent to instance
int someVariable = 1;
NSArray *winnerArray;
NSString *tempLoopString;
while(someVariable < 4){
tempLoopString = [NSString stringWithFormat:#"winnerArray%d", someVariable];
SEL selector = NSSelectorFromString(tempLoopString);
winnerArray = [self performSelector:selector];
if ([winnerArray do_stuff]) {
do stuff here
}
someVariable++
}
You can't refer to a variable by name like that.
You should look into using key value coding. With that, you can interrogate a property of some object using the method valueForKey:

Resources