Im making a class that creates a timer that then calls a void using #selector or (SEL). The app crashes when [mytimer timer…]; is called because "unknown selector called". The error is that it isnt finding the void I'm giving to it but i know that the void works fine. My question is how to I write the myselector part correctly?
+ (void) timer:(NSTimer*)timer interval:(int)interval selector:(SEL)myselector
{
timer = [NSTimer scheduledTimerWithTimeInterval:interval
target:self
selector:myselector
userInfo:nil
repeats:YES];
}
This is the method being implemented:
[mytimer timer:NameOfTimerTheWorks interval:0.1 selector:#selector(myVoid)];
...
- (void)myVoid
{
Do stuff
}
Also I understand that this class looks completely useless but there is more to it that I didnt include. My problem revolves around the selector.
There's nothing wrong with your use of #selector(), your issue is with Objective C classes, and what self means in different scopes.
The problem is that you're creating your timer in a class + method and self at that point is not the instance you want, it's actually the Class itself. I wouldn't be doing it in a class method, but if you must, just pass in the reference to the target and it should send th message your'e expecting.
Change your implementation to the following so you pass in the target, and return the timer
+ (NSTimer *)timerWithTarget:(id)target
interval:(int)interval
selector:(SEL)myselector
{
return [NSTimer scheduledTimerWithTimeInterval:interval
target:target
selector:myselector
userInfo:nil
repeats:YES];
}
NameOfTimerTheWorks = [mytimer timetWithTarget:self interval:0.1 selector:#selector(myVoid)];
- (void)myVoid
{
//Do stuff
}
Additionally, in Objective C the standard way to name classes is with a capital letter, and camel case where appropriate. Your class should be MyTimer and not mytimer and iVars are lowercase eg nameOfTimerTheWorks.
I believe the problem is that you're trying to access an instance level method using a class level method.
I changed + to - so that it was an instance level method.
If you wanted your method to be class level it would require that you make the method you want to call also class level.
- /* <-- + */(void) timer:(NSTimer*)timer interval:(int)interval selector:(SEL)selector
{
timer = [NSTimer scheduledTimerWithTimeInterval:interval
target:self
selector:selector
userInfo:nil
repeats:YES];
}
Related
I am using Objective-C, Xcode 4.5.1 and working on an app for the iPhone.
I have a method A in which I want to call another method B to do a series of calculations every x seconds. In method A I start playing an audio file. Method B will monitor the audio every x seconds for the duration of the audio file.
I have found NSTimer as a potential solution, but am having a hard time getting it to work/understanding it.
I simply want to call Method B every x seconds and run its calculations, but NSTimer requires me to provide several things of which I'm not sure what I'm supposed to tell it.
[NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)
target:(id) select:(SEL) userInfo:(id) repeats:(BOOL)];
It is my understanding that at NSTimeInterval I provide the interval at which I want NSTimer to operate. But, how do I tell it to run Method B?
I have looked at example code, and am currently under the impression that I provide the method at the 'select:'. But, what do I write at the 'target:'? Why would I need a target? I tried entering 'self', but Xcode tells me:
Use of undeclared identifier 'self'
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self
select:#selector(targetMethod:myVolumeMonitor()) userInfo:nil repeats:YES];
So, I figure 'self' is supposed to be a pointer to an object, but where do I want to point to?
Below is a simplification of my code:
MethodA()
{
//Start playing an audio file.
//NSTimer calling Method B, as long the audio file is playing, every x seconds.
}
MethodB()
{
//Do calculations.
}
I would be grateful if somebody could provide me with some answers/point me in the right direction! (:
Target is the recipient of the message named in select.
In Objective-C functions are not called. There are rather messages sent to objects. The Object internally refers to its symbol table and determines which of its methods is being called. That is a selector. Your selector is #selector(MethodB).
(BTW: you should start method names with lower case. "methodB" would be more appropriate here.)
This leads to the question: how to determine the object to which the message is sent? That is the target. In your case, it is simply self.
BTW: In this case the selector is expected to return void and accept an id, which is the id of the NSTimer object itself. That will come handy if you want the timer to stop firing based on some conditions according to your program logic.
Most important: Your selector is then methodB: rather than methodB.
- (void) methodA
{
//Start playing an audio file.
//NSTimer calling Method B, as long the audio file is playing, every 5 seconds.
[NSTimer scheduledTimerWithTimeInterval:5.0f
target:self selector:#selector(methodB:) userInfo:nil repeats:YES];
}
- (void) methodB:(NSTimer *)timer
{
//Do calculations.
}
try this
NSTimer *aTimer = [NSTimer timerWithTimeInterval:(x) target:self selector:#selector(timerFired:) userInfo:nil repeats:YES];
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:aTimer forMode: NSDefaultRunLoopMode];
[popUpImageView release];
- (void)timerFired:(NSTimer*)theTimer
{
if(condition)
{
[theTimer isValid]; //recall the NSTimer
//implement your methods
}
else
{
[theTimer invalidate]; //stop the NSTimer
}
}
If you look at your code and compared to the one below
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self
select:#selector(targetMethod:myVolumeMonitor()) userInfo:nil repeats:YES];
self means that you are invoking a method in same instance of your class, in your example the method is myVolumeMonitor
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self
selector:#selector(MethodB) userInfo:nil repeats:YES];
and you are good to go though
method be should look like this
- (void)MethodB:(NSTimer*)timer {
// do something
}
Well you are trying to call an normal C method, NSTimer can't to that.
The target is the an instance of the class on which to call the selector, this selector adn not select. The selector here is a SEL type which you can create with the #selector(METHOD_NAME) function.
For example this will call the handleTimer : ever 0.1 second: (For this example the AppDelegate is used):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//SNIP, some code to setup the windos.
[NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:#selector(handleTimer:) userInfo:nil repeats:YES];
return YES;
}
- (void) handleTimer:(NSTimer *)timer {
// Hanlde the timed event.
}
I am making an app where there is a test. I made a mistake of having different classes for each like 10 questions, to group them. Now I have a working stopwatch in the first class, but obviously it stops when i go to the next class (10 questions), how can I access the NSTimer in the other class from the new class and CONTINUE the timer. Here is my timer code:
- (void)viewDidLoad {
gameTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(gameTimerVoid) userInfo:nil repeats:YES];
[super viewDidLoad];
}
-(void)gameTimerVoid {
int now;
now = [gameTime.text intValue];
int after;
after = now + 1;
gameTime.text = [NSString stringWithFormat:#"%i", after];
}
In your case the timer seems the sharable assets across most of your files So you would consider having it in the separate class and could be accessed by any files (class) from there,then for doing such you need to use the singleton class design pattern,
Relocate the timer from your question group class to whatever class should logically manage the timer. It may seem like too much work to refactor your code now, but the pain will only get worse if you let this sort of problem fester.
The following piece of code refuses to compile because the method: "FollowPlayer" is a class method with class level access. How do I correctly allow NSTimer to call +(void)FollowPlayer?
- (void)awakeFromNib{zombie_size=4; timer=[NSTimer scheduledTimerWithInterval: 1.0 target:self selector:#selector(FollowPlayer) userInfo:nil repeats: NO];}
+ (void)FollowPlayer: NSTimer{}
Change the target from 'self' to [MyClass class] where MyClass is the name of your class.
Hey. Can you check that the method you are calling is scheduledTimerWithTimeInterval ? Your code has it calling scheduledTimerWithInterval ... missing the Time part
Are you sure it's not just a syntax error? Can you do this?
- (void)awakeFromNib{zombie_size=4; timer=[NSTimer scheduledTimerWithInterval: 1.0 target:self selector:#selector(FollowPlayer:) userInfo:nil repeats: NO];}
+ (void)FollowPlayer:(id)userInfo { NSLog(#"Timer called with user info %#", userInfo); }
This is a really dumb question. How would you pass an object to a method using an NSTimer?
I mean something like this -
I have a method in BigView.m that has a method called doSomethingWithClass:.
- (void)doSomethingWithClass:(CustomClass *)class {
NSLog(#"Something was done");
}
In another class called CustomClass, I have an NSTimer -
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:bigView selector:#selector(doSomethingWithClass:) userInfo:nil repeats:NO];
Where bigView is an instance of BigView. Now I want to pass an entire instance of CustomClass as the parameter in the method doSomethingWithClass:. How do I do it?
If you don't need to refer to the timer, use the simpler performSelector:withObject:afterDelay: method.
[bigView performSelector:#selector(doSomethingWithClass:)
withObject:customClass
afterDelay:0.5];
(To cancel it, use +cancelPreviousPerformRequestsWithTarget:….)
I'm trying to access an NSTimer in a method called getTimer in another method.
- (NSTimer *)getTimer{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector: #selector(produceBricks) userInfo:nil repeats:YES];
return timer;
[timer release];
}
I'm trying to stop the timer in another method (a method that would pause the game) by using:
if ([getTimer.timer isValid]) {
[getTimer.timer invalidate];
}
I'm assuming this is not the correct syntax being it tells me getTimer is undeclared. How would I access the timer so I can stop it?
getTimer is a method, not an object, so you can't send messages to it or access properties. Rather, assuming that the method is in the same class as the one calling it, you would call it like this:
NSTimer *timer = [self getTimer];
if ([timer isValid]) [timer invalidate];
//...
Also, you're trying to release your timer in the getTimer method after the return statement. This code will never be executed (the method has already ended) - which is good in this case, because you shouldn't release the timer, it's already autoreleased. I'd recommend that you read something on Objective-C memory management and naming conventions.
Make the timer an instance variable instead of creating in within getTimer. Then it will be accessible anywhere within the class as follows:
in MyClass.h
NSTimer* timer;
I would implement a startTimer and stopTimer method.
- (void) startTimer {
timer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector: #selector(produceBricks) userInfo:nil repeats:YES];
}
- (void) stopTimer {
if([timer isValid]) {
[timer invalidate];
}
}