I am trying to build an iPhone app. I created a
method like this:
- (void)score {
// some code
}
and I have tried to call it in an other method like this:
- (void)score2 {
#selector(score);
}
But it does not work. So, how do I call a method correctly?
To send an objective-c message in this instance you would do
[self score];
I suggest you read the Objective-C programming guide
Objective-C Programming Guide
I suggest you read The Objective-C Programming Language. The part about messaging is specifically what you want here, but the whole thing will help you get started. After that, maybe try doing a few tutorials to get a feel for it before you jump into making your own apps.
calling the method is like this
[className methodName]
however if you want to call the method in the same class you can use self
[self methodName]
all the above is because your method was not taking any parameters
however if your method takes parameters you will need to do it like this
[self methodName:Parameter]
I think what you're trying to do is:
-(void) score2 {
[self score];
}
The [object message] syntax is the normal way to call a method in objective-c. I think the #selector syntax is used when the method to be called needs to be determined at run-time, but I don't know objective-c well enough to give you more information on that.
Use this:
[self score]; you don't need #sel for calling directly
syntax is of objective c is
returnObj = [object functionName: parameters];
Where object is the object which has the method you're calling. If you're calling it from the same object, you'll use 'self'. This tutorial might help you out in learning Obj-C.
In your case it is simply
[self score];
If you want to pass a parameter then it is like that
- (void)score(int x) {
// some code
}
and I have tried to call it in an other method like this:
- (void)score2 {
[self score:x];
}
use this,
[self score];
instead of #selector(score).
[self score]; instead of #selector(score)
Related
I'm new to iPhone application development, but I seem to have somewhat managed so far (learning as I go).. however, I've run in to an issue I can't figure out. Here's the scenario:
I have an extension class called CoreAPI which I have my network functions inside. I have a function called "Login" inside CoreAPI which makes a request to a server, gets the 0 or 1 response and returns true or false. I had this working perfectly with Synchronous requests, but now I need to make everything asynchronous.
So, below is what I'm trying to do.. this is not working with the error along the lines of "Object of type ID has no method loginCallback"
loginViewController.m
- (void) login {
CoreAPI APIObject = [[CoreAPI alloc] init];
[APIObject login:self];
}
- (void) loginCallback {
NSLog(#"It called back.");
}
CoreAPI.m
- (void)login:(id)sender {
[sender loginCallback];
}
Thanks, and please let me know if I have missed any details needed to help me.
I'm seeing a couple problems. First, I'm guessing you don't provide visibility of the loginCallback function to CoreAPI.m. You should be able to send any message to an id type, so long as it's defined for a known type.
However, I'd recommend using a completion block in this case. Here's what that could look like:
(in CoreAPI.h)
- (void)login:(void (^)(void))completed;
(in CoreAPI.m)
- (void)login:(void (^)(void))completed {
// Login code
if (completed) completed();
}
Calling it would look like:
CoreAPI APIObject = [[CoreAPI alloc] init];
[APIObject login:^{
NSLog(#"It called back.");
}];
They have really goofy syntax, but blocks are really nice for this sort of thing. Hope this helped! Let me know if I didn't explain something clearly.
this should do the trick for you:
first, import loginViewController header inside CoreApi.m
#import "loginViewController.h"
Then, change login method to this:
- (void)login:(id)sender {
[(loginViewController*)sender loginCallback];
}
Or this:
- (void)login:(loginViewController*)sender {
[sender loginCallback];
}
Explanation: notice that your login method is receiving by parameter one object of type id . In objective C, id type means a reference to any Objective-C of unknow class. So, inside your login method, the compiler doesn't know that the sender is a instance of your loginViewController class, so it won't recognize loginViewController's methods.
To informations about this, please read: Objective-C: difference between id and void *
Notice that I only focused in remove your actual error. You should have to do more things in order to accomplish your code to run asynchronous.
In order to perform a better callback, please look for delegates or blocks (like in oltman's answer).
To run things in background, look for CDG : http://developer.apple.com/library/ios/#DOCUMENTATION/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
I have spent quite a bit of time reading about blocks, but for some reason it's very difficult for me to fully understand them. It's worth mentioning I'm a newbie developer, but blocks are the first real 'block' I've come across, so maybe you can help me.
I have a case where an object (instance of a ViewController) is talking to a class (via a class method - it's a utility class I've set up to request/get data). I want to implement a method with a callback using a block. Here are my current 'understandings' that I based my code on:
A block can be passed as a method argument;
A block can be called like a function.
OK, so here's my (simplified) method in my utility class:
+ (void)getDataWithCompletion:(void (^)(BOOL))completion {
//Some code...
completion(YES);
}
And this is how I call the method from my viewController:
[ClassName getDataWithCompletion:^(BOOL gotData) {
if (gotData) {
NSLog(#"Called");
}
}];
Naturally, I was expecting that NSLog to be printed on my console, but alas... I know I am doing something wrong here, could someone please point that out? Any rookie-level explanation would be highly appreciated.
The mistake is really simple. You forgot a parameter name.
Cahnge your method to this.
(BOOL gotData) this is what you have missed.
+ (void)getDataWithCompletion:(void (^)(BOOL gotData))completion {
//Some code...
completion(YES);
}
Here is link to apple documentation apple block documentation
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;
i've got this method:
-(void)reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent
now I want to call this method in another method like:
[self thisMethod];
But how can I do this with a method that has local declarations in it?
thank you
It doesn't matter if a method has local declarations in it, that's completely normal. Have you tried calling [self thisMethod];? Does it crash?
I'm new to Cocoa/Cocoa Touch, and working through a development book. I've come across situations where the #selector() operator is used. I'm a bit lost on how and when the #selector() operator should be used. Can someone provide a short and sweet explanation and example of why it's used and what benefit it gives the developer?
By the way, here is sample code taken from Apple's iPhone development site that uses #selector()
if ([elementName isEqualToString:#"entry"])
{
parsedEarthquakesCounter++;
// An entry in the RSS feed represents an earthquake, so create an instance of it.
self.currentEarthquakeObject = [[Earthquake alloc] init];
// Add the new Earthquake object to the application's array of earthquakes.
[(id)[[UIApplication sharedApplication] delegate]
performSelectorOnMainThread:#selector(addToEarthquakeList:)
withObject:self.currentEarthquakeObject waitUntilDone:YES];
return;
}
The selector operator provides a way to refer to a method provided by an object, somewhat similar to a function pointer in C. It is useful because it allows you to decouple the process of calling methods on an object. For example one piece of code could provide a method, and another piece of code could apply that method to a given set of objects.
Examples:
Test to see if an object implements a certain method:
[object respondsToSelector:#selector(methodName)]
Store a method to later call on an object;
SEL method = #selector(methodName);
[object performSelector:method];
Call a method on a different thread (useful for GUI work).
[object performSelectorOnMainThread:#selector(methodName)]
In addition to what's been said, you can also wrap up the #selector in an NSInvocation for later use. You can set the arguments to the NSInvocation a long time after it's created, and activate it when you need the message to be fired. This gives you a lot of power.
For an introduction to the concept, Scott Stevenson has a great post entitled "Dynamic Objective-C with NSInvocation".
#selector() is used each time you need to pass the name of a method as an argument to another method, a function or as a variable value. Passing directly the name doesn't work in objective-C.
One practical example is validateMenuItem method where menu items are identified with their target actions.
Simplified example:
- (BOOL)validateMenuItem:(NSMenuItem *)item {
if ([item action] == #selector(selectFiles:) && otherCondition) {
return YES;
} else {
return NO;
}
}
One reference to look at:
http://en.wikipedia.org/wiki/Multiple_dispatch
You can use a selector to invoke a method on an object—this provides the basis for the implementation of the target-action design pattern in Cocoa.
[myObject performSelector:#selector(runMYmethod:) withObject:parameters];
is equivalent to:
[myObject runMYmethod:parameters];