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;
}
Related
A strange situation:
If I started my Timer again and again without stopping it first, it will count increasingly fast. I guess it is because it starts multiple timers now?
However, when I finally want to stop it, it cannot be stopped...keep going forever.
(Maybe for design consideration, I should disable users from pressing start again, but I'm wondering what is really behind this and why the timer can't be stopped.)
- (IBAction)Start:(id)sender {
countInt = 0;
self.Time.text = [NSString stringWithFormat:#"%i", countInt];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countTimer) userInfo:nil repeats:YES];
}
- (IBAction)Stop:(id)sender {
[timer invalidate];
}
- (void) countTimer {
countInt += 1;
self.Time.text = [NSString stringWithFormat:#"%i", countInt];
}
#end
The simple solution is to call stop at the beginning of the start method.
Note that in stop you should also set timer = nil;
Assuming there is a property timer
#property NSTimer *timer;
the most reliable way to start and stop the timer only once respectively is to create two methods.
- (void)startTimer
{
if (self.timer == nil) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(countTimer)
userInfo:nil
repeats:YES];
}
}
- (void)stopTimer
{
if (self.timer != nil) {
[self.timer invalidate];
self.timer = nil;
}
}
Both methods perform a check, so the timer can't be restarted while it's running and vice versa.
Now just call the methods in the start/stop IBActions (the names should start with a lowercase letter).
- (IBAction)Start:(id)sender {
countInt = 0;
self.Time.text = [NSString stringWithFormat:#"%i", countInt];
[self startTimer];
}
- (IBAction)Stop:(id)sender {
[self stopTimer];
}
The benefit is pressing Start has no effect when the timer is already running.
When you hit 'start' multiple times you are creating multiple timers. So you are getting multiple timers firing and executing your timer callback. In this timer callback you increment counters. Since there are many timers now, they are all incrementing your counter, hence explaining your rapid increase in the counter.
You can allow the user to tap Start twice, as long you can define what happens when you hit Start while the timer is already going. But you definitely need to invalidate the old timer before creating a new one.
- (IBAction)Start:(id)sender {
...
// Stop previous timer before creating a new timer.
if (timer != nil) {
[timer invalidate]
}
...
}
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;
}
}
I make one 30:00 min countdown timer, now when I load next page and back on first page my timer is on but label which show time it's stopped.
Any idea for that when I come on first page and my timer is on and start at same point, in short I need run my timer in background.
This is the code which I use in same view controller where the timer is, but it's not working.
- (void)viewWillDisappear:(BOOL)animated
{
[Timecount invalidate];
}
-(void)viewDidAppear:(BOOL)animated
{
// [self countdownTimer];
}
-(void)viewWillAppear:(BOOL)animated
{
[self countdownTimer];
}
-(void)countdownTimer
{
secondsLeft = hours = minutes = seconds = 0;
if([Timecount isValid])
{
}
Timecount = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
}
I have an IBAction:
- (IBAction)stop:(id)sender {
NSLog(#"Called");
if (timer) {
[timer invalidate];
timer = nil;
}
}
This should stop the timer that is running, I've included the NSLog to to see if my invalidating of the timer is bad or if the method isn't even being called, and, it's not being called. I have my button connected to the "Touch Cancel" method in storyboard, is there anything I can do to make this work? Also, I have a "Touch Down" method for the timer to start:
- (IBAction)begin:(id)sender {
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:#selector(doSomething:) userInfo:nil repeats:YES];
}
To have a UIButton fire off an IBAction when it is pressed and released you will want to use the "Touch Up Inside" sent event and not "Touch Cancel".