Unrecognized selector error with performSelector: method - objective-c

I call
[delegate addText:button.titleLabel.text withSelector:#selector(addElement:) fromKeyboard:self.name]
which corresponds to
- (void)addText:(NSString *)text withSelector:(SEL)selectorName fromKeyboard:(NSString *)name {
[tempData performSelector:#selector(selectorName) withObject:text];
}
However, when I call the perform selector method on tempData, I get the error. When I replace selectorName with (addElement:) it works fine.

You only write like that
[tempData performSelector:selectorName withObject:text];
it is already a selector so you dont need to write #selectr(...)

#selector(selectorName)
you forget :
#selector(selectorName:)

It seems there is a bit of confusion around the #selector() construct here:
The #selector(selectorName) is a literal for the selector with the name inside the braces,
selectorName in this case (much like "selectorName" is a literal for the C string inside the quotes. This means that you are trying to send selector named selectorName to the tempData object, which fails.
If you want to pass in the selector to send by name, use the NSSelectorFromString() function:
- (void)addText:(NSString *)text withSelector:(NSString *)selectorName fromKeyboard:(NSString *)name {
[tempData performSelector:NSSelectorFromString(selectorName) withObject:text];
}
It might be a good idea to make sure the receiver responds to the selector in this case by using -respondsToSelector:

Related

How to Create a Dynamically Named Selector inside a Method

I have an objective C method which passes in a string and an integer as its arguments. Inside of this method, I want to use a selector - the name of which is based upon the integer value I am passing in. For example, if the integer argument is 5, I want the selector to be named "buildXArrayIndex5" or if the integer argument is 3, I want the selector to be named "buildXarrayIndex3." I am really at a loss for how to do this or if it is possible/reasonable. I am new to objective C, so I wrote out what I want to happen, but it is not working/valid code. But here it is:
- (void) startBuildingXArray:(int)senderID:(NSString *)moveTrackerObject {
NSString *methodNamePrefix = #"buildXArrayIndex";
NSString *realMethodName = [[NSString alloc]initWithFormat:#"%#%d",methodNamePrefix,
senderID];
SEL realSelector = NSSelectorFromString(realMethodName);
[self realSelector: moveTrackerObject];
}
In the interface, I declared SEL realSelector; but I am getting an error without running this that says"no visible #interface declares the selector realSelector." But I'm sure that this is not the only problem with this code. Can anyone tell me how to create the proper code for this or highlight a better approach?
You need to call your selector using -performSelector: method, e.g.:
[self performSelector:realSelector];
Also if methods you want to call accept parameter you need to add a colon to selector name:
NSString *realMethodName = [[NSString alloc]initWithFormat:#"%#%d:",methodNamePrefix, senderID];
and call it:
[self performSelector:realSelector withObject:moveTrackerObject];

XCODE pass a method as parameter

I wan't to pass a method as a parameter to another method, so it know the method to call when ends running. Is it possible?
[self bringJSON:(NSString *)_passedValua:(NSObject *)anotherMethod];
As #Daniel mentioned in comments you can use selector for that. Basic scheme will be the following:
// Method declaration - method accept selector as parameter
- (void) bringJSON:(NSString *)_passedValua toMethod:(SEL)anotherMethod];
// Method call - create selector from method name (mind the colon in selector - it is required if your method takes 1 parameter)
[self bringJSON:jsonString toMethod:#selector(methodName:)];
// Implementation
- (void) bringJSON:(NSString *)_passedValua toMethod:(SEL)anotherMethod]{
...
if ([target respondsToSelector:anotherMethod])
[target performSelector:anotherMethod withObject:_passedValua];
}

Variable out of IBAction

I have problem that im trying to get solve for like week.
My goal is to get variable out of my IBAction, to use for example in -(void)viewDidLoad..
But as far as I am now I can use my variable only in my IBAction..
- (IBAction) changeLat:(NSNumber *)str {
longi = str;
double lop = longi.doubleValue;
NSLog(#"%f",lop);
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog (#"%#",lop);
}
It NSLog shows everything fine in action, but in view did load it doesn't even recorganize it.
If you create a variable inside of -IBAction, the scope of that variable is only that method, so you cannot access to that variable outside it.
If you want your variable to be global to your class, you have to create it in the declaration of your class, like this:
#interface MainViewController () {
#private
double lop;
}
Put this at the beginning of your .m file, and then lop would be accesible in all your class.
You can read more about the scope of the variables here:
http://www.techotopia.com/index.php/Objective-C_Variable_Scope_and_Storage_Class
Actually, IBAction is converted to void by the preprocessor. It's used by Interface Builder as a label that identifies this method as an action able to be related from an IB Object.
There's no way (AFAIK) to use two return types in a function (for example `(IBAction double)´, equivalent to ´(void double)´), but a good practice could be something like this:
- (IBAction)changeLatAction:(id)sender {
NSNumber *str = <get the NSNumber from a valid place>;
[self changeLat:str];
}
- (double) changeLat:(NSNumber *)str {
longi = str;
double lop = longi.doubleValue;
NSLog(#"%f",lop);
return ????;
}
Your first declaration of changeLat seems to be wrong, because as a first parameter you'll always get the "sender" or "caller" object, related from IB (when called from an action, of course), so, you need to get the str value from a valid place.
Cheers.

Selectors in Cocos2d schedule method

So I am doing this to initialize my selector:
//In .h
SEL selectors[3];
//In .m
selectors[0] = #selector(rotate);
selectors[1] = #selector(discharge);
And here is the problem:
When I call this in my init method in Cocos2d like this:
[self performSelector:selectors[0]];
it works fine, but when I call this line of code in a method called moveThings which is invoked through the schedule ([self schedule:#selector(moveThings:)]) at the end of my init method in Cocos2d it gives EXC_BAD_ACCESS. What is the problem with scheduling things?
UPDATE:
I have found there is a problem with the rotate function (the function being stored in selector[0]). Here it is:
-(void)rotate:(ccTime)delta {
if (((CCSprite *)[creature objectAtIndex:0]).rotation < 360) {
((CCSprite *)[creature objectAtIndex:0]).rotation++;
}
else {
((CCSprite *)[creature objectAtIndex:0]).rotation++;
}
}
If I comment the contents of the method out it works fine when called through moveThings and init.
If I change the methods contents with:
((CCSprite *)[creature objectAtIndex:0]).rotation++;
It fails... But, again, I would like to state that all of these things do work if I call it in my init method, even call it twice in a row, but it will not work (except when I take out the contents of the rotate method) if I call it through the moveThings: method which is being invoke through the schedule method it fails.
Further update:
If I call:
((CCSprite *)[creature objectAtIndex:0]).rotation++;
In moveThings (which is being, as I've said before, invoked by the schedule:(SEL) method) it fails. Where as long as it is not invoked through a method that is the called by schedule it works.
The problem is that when you call performSelector there are only two options:
have your selector take no arguments and leave the ":" off the #selector(foo) definition.
have your selector take either one or two arguments which both must be an NSObject or subclass
it is the latter that is messing you up here I suspect.
Here are the three forms of performSelector:
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
You'll note that the withObject arguments are all of type id which is an Objective C object.
The selector you're trying to use takes a ccTime which is a float and not an Objective C object as it's param and that is why things are crashing:
-(void)rotate:(ccTime)delta;
One option is to make a wrapper method that takes a wrapped ccTime and unwraps it and calls the rotate:(ccTime) method:
- (void) wrappedRotate: (NSNumber*) inDelta
{
[self rotate: [inDelta floatValue]];
}
then use
selectors[0] = #selector(wrappedRotate:);
and then call via:
[self schedule: #selector(moveThings:)]); // cocos2d schedule
...
- (void) moveThings: (ccTime) dt
{
[self performSelector: selectors[0] withObject: [NSNumber numberWithFloat: dt]];
...
}
One reason you are getting confused is because Cocos2d is using #selector in somewhat more complicated ways (see CCScheduler.m in the CCTimer::initWithTarget:selector:interval: and CCTimer::update: method in particular).
disclaimer: code typed into SO so not checked with a compiler, but the essence of what you need should be here.
One problem for sure is that you are using a variable declared inside a .h while initializing it inside the relative .m. According to the linking I'm not sure that just one variable selectors will exist (so that different files that include .h will have different versions).
First of all I suggest you to try adding the keyword extern to have
extern SEL selectors[3];
to tell your linker that it is initialized inside the relative .m and to use just that one.
I think your problem stems from your method definition which is - (void)rotate; and not - (void)rotate:(ccTime)dt;
You should adjust your selectors likewise.
If your method does not have any arguments then do not use a colon in your selector call.
// Requires #selector(foo:)
- (void) foo:(id)sender;
// Requires #selector(foo)
- (void) foo;

Comparing strings in IF statements: unrecognised selector sent to instance

in my code, I need to compare two strings to see if they are equal. if they are it needs to preform a function. one of the strings is just a #"someString", the other is part of an object.
if ([[[mine metal] stringValue] isEqualToString:#"Gold"])
{
//some function
}
however there are some complications when I do this. first, it gives me a warning: NSString may not respond to -stringValue. and when I run the Application it quits out at the if statement: the console reports " -[NSCFString stringValue] : unrecognized selector sent to instance." mine.metal is defined through a fast enumeration loop across an array; the metal attribute is defined as an NSString, and NSLog is able to display this string. what else am I missing?
The compiler warning and the subsequent run-time error both tell you what the problem is.
[mine metal] returns an NSString. NSString doesn't have a method called stringValue.
If [mine metal] does indeed return an NSString then you can do this:
if ([[mine metal] isEqualToString:#"Gold"])
{
//some function
}