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];
}
Related
As my title states, I'm wondering if I can pass a method signature or an #selector as a parameter? I'm asking because I'm creating a framework and I want to be able to pass instances of a certain class within it a method name.
You can pass the selector itself of use the name of the method as a string:
- (void)myMethod:(SEL)selector
{
[aClass performSelector:selector];
}
or
NSString *myMethodName = NSStringFromSelector(#selector(myMethod));
NSLog(#"The name of the method is: %#", myMethodName);
Actually, you cannot not pass a selector to a method.
In Objective-C, every method gets two implicit arguments, passed as normal parameters: The instance pointer self and the target selector _cmd. They are present in each and every method. The _cmd parameter is of type SEL. It is used by the runtime to look up the method implementation (this is the core of objc's dynamism).
You can, of course, add additional parameter of SEL type.
I'm trying to declare a function within another function. So here's part of my code:
ViewController.m
- (void)updatedisplay{
[_displayText setText:[NSString stringWithFormat:#"%d", counter]];
}
- (IBAction)minus1:(id)sender {
counter--;
updatedisplay();
}
ViewController.h
- (IBAction)minus1:(id)sender;
- (void)updatedisplay;
Which returned me the error of "Implicit declaration of function "..." is invalid in C99".
Result: http://i.imgur.com/rsIt6r2.png
I've found that people have encountered similar problem, but as a newbie I didn't really know what to do next. Thanks for your help! :)
Implicit declaration of function '...' is invalid on C99
You are not declaring a function; but a instance method, so to call it you must send it as a message to self;
[self updatedisplay];
EDIT
As #rmaddy pointed out (thanks for that) it is declared as instance method not class method. To make the things clear;
- (return_type)instance_method_name.... is called via 'self' or pointer to object instance.
+ (return_type)class_method_name.... is called directly on the class (static).
Problem
updatedisplay();
solution
[self updatedisplay];
cause
- (void)updatedisplay;
is a class method available for that class.So you have to call from the class to have the method available for you.
That is because you defined your function as a instance method, not a function.
So use it like
- (IBAction)minus1:(id)sender {
counter--;
[self updatedisplay]; // Change this line
}
write this way :
[self updatedisplay];
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:
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;
In the following code, I passed the "1.3f" to printFloat, but it was the wrong value (in this case, -2.000000) after was "f" received. And there is a warning that "AppDelegate may not respond to -printFloat:"
Where did I get it wrong?
- (void)applicationDidFinishLaunching:(UIApplication *)application{
// Override point for customization after application launch
[window makeKeyAndVisible];
[self printFloat:1.3f];
}
- (void)printFloat:(float)f {
NSLog(#"%f",f);
}
You can easily resolve both your problems by adding the method prototype into the header file (<sameName>.h):
- (void)printFloat:(float)f;
If you include the correct definition in the class' header file, and you still cannot pass floats by reference, make sure you're not overriding an existing method of a parent class...
For example, I had this problem because my class was derived from NSMutableData (which I did not know then), and I added a method,
- (void) initWithLength:(float)length;
to my class. NSMutableData already defines this method, and it uses an integer.
My method then produced garbage: the float value was passed as 0x0 no matter what I sent it...