I have an NSTimer that I want to be stopped when I leave my vViewVontroller:
The timer is in a method that I call from viewWillAppear :
- (void) myMehtod
{
//timer = [[NSTimer alloc] init];
// appel de la methode chaque 10 secondes.
timer = [NSTimer scheduledTimerWithTimeInterval:10.0f
target:self selector:#selector(AnotherMethod) userInfo:nil repeats:YES];
//self.timerUsed = timer;
}
I call the method stopTimer in viewWillDisappear
- (void) stopTimer
{
[timer invalidate];
timer = nil;
}
PS: I tried the answer of user1045302 in this question but it didn't work:
How to stop NSTimer
The source of the problem probably is that myMehtod is called twice or more times.
Since the method does not invalidate existing timers before setting up the new one you actually have several timers ticking at the same time.
Fix is easy: invalidate old timers before setting up a new one:
- (void)myMehtod
{
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval:10.0f
target:self
selector:#selector(anotherMethod)
userInfo:nil
repeats:YES];
}
I have a timer declared like so:
#property (nonatomic,strong) NSTimer* tutorialTimer;
...
self.tutorialTimer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(showTutorial) userInfo:nil repeats:YES];
when clicking on a button I'm stopping the timer(or at least wish to stop) like so:
[self.tutorialTimer invalidate];
self.tutorialTimer = nil;
the timer keeps invoking...suggestions?
NSTimer should work in main Thread .
you can check the process use code
if ([NSThread isMainThread])
{
[self.tutorialTimer invalidate];
self.tutorialTimer = nil;
}
to find out whether if it can step into [self.tutorialTimer invalidate];
I use this code for stopping NSTimer
[timer invalidate]
timer = nil;
It works fine for the first run. But, after I resume the timer with this code.
timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(checkNewUpdates)
userInfo:nil
repeats:YES];
NSTimer won't stop anymore with [timer invalidate]
It look like multiple instance of timer is running simultaneously. You can do one thing, before start to run a new timer, check for previous instance of timer, and if timer instance is available, then invalidate it. After this start new instance
if(timer)
{
[timer invalidate];
timer = nil;
}
timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(checkNewUpdates)
userInfo:nil
repeats:YES];
In apple's official document they said:
You must send this message from the thread on which the timer was
installed. If you send this message from another thread, the input
source associated with the timer may not be removed from its run loop,
which could prevent the thread from exiting properly.
If your timer is running on main thread, do this:
[timer performSelectorOnMainThread:#selector(invalidate) withObject:nil waitUntilDone:YES];
If it is on any other thread, lets call the thread myThread, then do this:
[timer performSelector:#selector(invalidate) onThread:myThread withObject:nil waitUntilDone:NO];
Hope this helps.. :)
Just invalidate the timer inside the selector that fires. That will ensure you have a pointer to the correct timer (which is probably why your invalidate call isn't working:
timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(checkNewUpdates:)
userInfo:nil
repeats:YES];
Note the colon after checkNewUpdates:
Then, in your checkNewUpdates: method, do something like this:
- (void)checkNewUpdates:(NSTimer*)timer
{
// do somehting
// Then, check if the criteria for stopping the timer has been met, and invalidate it here.
if( self.shouldStopTimer ) // made up variable, use your own criteria.
{
[timer invalidate];
}
}
I know this doesnt answer your question per-se;
Can I suggest using polling mechanism instead of a timer? Ive had a world of trouble with NSTimers in the past and polling was a good alternative. Ive made a simple one below.
- (void) doPoll {
// do logic here
if (shoudStop) {
return;
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, X * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
[self doPoll];
});
}
This is just a simple example, it does not stop retain cycles If you choose to try this, Yours should.
Hope it helps.
#property (weak, nonatomic) NSTimer *timer;
-void()timerMethod
{
...some stuff
[self.timer invalidate];
self.timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(refreshScreen:) userInfo:nil repeats:NO];
}
-void(refreshScreen:id(sender)
{
...some stuff that calls other methods one of which calls timerMethod to continue the process
}
-(void)viewWillDisappear:(BOOL)animated
{
[self.timer invalidate];
self.timer = nil;
}
When I move to a new VC, viewWillDisappear is called and I confirm that
1/ timer is invalidated (using [self.timer isValid].
2/ We are on the main thread (using [NSThread isMainThread]
3/ timer is Nil
The timer itself when created is also confirmed on the main thread.
Some seconds later on the other VC, the timer calls the "refreshScreen" method regardless of the above.
I have checked that the invalidate within timerMethod is invalidating with each pass. I am doing this to ensure that more than 1 timer is not created. Breakpoints show that although the timer goes invalid and nil upon exit, once it calls "refreshScreen" again it has reestablished the timer and is no longer nil despite the fact that its VC was dismissed.
So I have this code:
int i = 3;
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
for (;;)
{
t1 = [NSTimer scheduledTimerWithTimeInterval:i target:self selector:#selector(updateUI) userInfo:nil repeats:NO];
}
});
});
And so what i'm doing is i'm updating the UI every 3 seconds in a game, but I want to be able to change the interval on which the timer goes off so I used an infinite for loop with the timer in it. My problem is that when I use the main queue it doesn't do it async but I need to use the main queue for updating the UI so I don't know what to do.
If you create NSTimer in main thread, then selector call in main thread.
- (void)updateTimer
{
// destroy timer
[t1 invalidate];
// start new timer
t1 = [NSTimer scheduledTimerWithTimeInterval:i target:self selector:#selector(updateUI) userInfo:nil repeats:NO];
}
- (void)updateUI
{
......
[self updateTimer];
}
Need call [self updateTimer] in start application, to begin the update UI.