I have added nstimer in my app.I have set it's repeat property to YES.I am trying to stop timer when i click on button but timer does not stopping in that case.
image_timer_one= [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(ImageTimer:)userInfo:nil repeats:YES];
code to stop timer
[image_timer_one invalidate];
image_timer_one=nil;
But timer does not stop.Please tell how can i stop the timer.
EDIT:
I trying to give cursor animation effect so i am setting a new image when timer repeats here is the code.
-(void)ImageTimer:(NSTimer*)timer{
if(mode_count==0)
{
if(img_time==0)
{
[self.pass_image_1 setImage:[UIImage imageNamed:#"blink_2.png"]];
img_time=1;
}
else if(img_time==1)
{
[self.pass_image_1 setImage:[UIImage imageNamed:#"blink_1.png"]];
img_time=0;
}
}
}
try this and before starting timer stop previous timer action with calling ImageTimer method.
if (image_timer_one != nil && [image_timer_one isValid]) {
[image_timer_one invalidate];
image_timer_one = nil;
}
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];
}
So I've got a timer that is not repetitive. Each time it fires, the method that being executed decide if to reschedule it or not according to some inner logic of my app.
This method is available from other parts of the app, so the first thing that I'm doing in the method is to check if the timer is still valid (to know if the initiator was the timer or a different entity) so in case it wasn't initiated by the timer I want to invalidate it:
if (self.pollingTimer.isValid) {
[self.pollingTimer invalidate];
self.pollingTimer = nil;
}
I've noticed that if the method is being called due to the timer being fired - I always receive a true value from the isValid property, even though when looking at the NSTimer documentations under the scheduledTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats method:
repeats
If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires.
Discussion
After seconds seconds have elapsed, the timer fires,
sending the message aSelector to target.
I'm having hard time to understand when the timer is being automatically invalidated which bring me to my questions:
Any idea why I always get YES from isValid?
What is the exact definition of the timer fires? Is it just sending the message aSelector to target as stated in the documentation? or is it finishing the execution of the method? (which might explain what I'm experiencing)
Thanks in advance.
A timer is not a real-time mechanism; it fires only when one of the run loop modes to which the timer has been added is running and able to check if the timer’s firing time has passed. Therefore, the timer does not immediately invalidate itself, but at the end of the run loop.
As a simple test, you can see:
- (void)viewDidLoad {
[super viewDidLoad];
_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(timerFired) userInfo:nil repeats:NO];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self.timer.isValid){
NSLog(#"--> TIMER VALID");
} else {
NSLog(#"TIMER INVALID!");
}
});
}
- (void) timerFired {
if (self.timer.isValid){
NSLog(#"--> TIMER VALID");
} else {
NSLog(#"TIMER INVALID!");
}
}
This will log --> TIMER VALID from the timerFired method and when the block from dispatch_after is called, you will see TIMER INVALID!. So, when you schedule a timer with repeats:NO, it is guaranteed to not reschedule itself but it will not invalidate immediately.
So, to answer your question:
repeats
If YES, the timer will repeatedly reschedule itself until
invalidated. If NO, the timer will be invalidated after it fires (but not immediately)
I made a test like this:
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(xx) userInfo:nil repeats:NO];
- (void)xx
{
if ([self.timer isValid]) {
NSLog(#"isvalid");
}
dispatch_async(dispatch_get_main_queue(), ^{
if ([self.timer isValid]) {
NSLog(#"isvalid");
}else{
NSLog(#"isInvalid");
}
});
static int i = 0;
NSLog(#"%d",i++);
}
and the result is:
isvalid
0
isInvalid
thus, I guess when timer is fired,the function is execute like this:
void __NSFireTimer(){
id yourObj;
[yourObj performSelector:#selector(yourSelector)];
timer.isvalid = NO;
}
what you believe is:
void __NSFireTimer(){
id yourObj;
timer.isvalid = NO;
[yourObj performSelector:#selector(yourSelector)];
}
So, just accept it.You can put your check valid code in dispatch_asyn() ,like the test code.
This is how I used my timers. First initialise it on the top as
#property (strong, nonatomic) NSTimer *refreshTimer;
then this two methods, to create and invalidate the timer. "Its very important to invalidate the current timer if you want to create another timer with same name" otherwise their will be two timers.
- (void)startTimer {
if (_refreshTimer) {
[self invalidateTimer];
}
_refreshTimer = [NSTimer scheduledTimerWithTimeInterval:15.0
target:self
selector:#selector(determineIfPartOfgroup)
userInfo:nil
repeats:YES];
}
- (void)invalidateTimer {
if (_refreshTimer) {
[_refreshTimer invalidate];
_refreshTimer = nil;
}
}
I hope this will help you.
I am starting a timer to trigger an event based on a false condition.However if the condition becomes true within the scheduled time, i need to stop the event from triggering.
if(!condition)
{
myTimer =[NSTimer scheduledTimerWithTimeInterval:200 target:self selector:#selector(trigger:) userInfo:nil repeats:NO];
}
else
{
if([myTimer isvalid])
[myTimer invalidate]
myTimer= nil;
}
If condition becomes true within 200 sec don't trigger the #selector.
Invalidating the timer doesn't stop the method from triggering. I can do this by having a BOOL flag, but can i do it using NSTimer's methods.
You must be creating multiple instance of myTimer. Check whether myTimer already initailized or not ?
if(!condition)
{
if(myTimer == nil)
myTimer =[NSTimer scheduledTimerWithTimeInterval:200 target:self selector:#selector(trigger:) userInfo:nil repeats:NO];
}
else
{
if([myTimer isvalid])
{
[myTimer invalidate]
myTimer = nil;
}
}
#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.