I have a NSTimer that functions as a stopwatch. It makes the time count and has the pause function that works properly but the function does not work continue. The timer seems to be counting even paused but not updated the label and when I touch the button comes down to is to continue from where you left it continues counting that did not stop. How can I fix this?
this is my chronometer code:
- (void)viewDidLoad {
[super viewDidLoad];
[self setUp];
self.isPaused = NO;
}
- (void) setUp {
startDate = [NSDate date];
_timer = [NSTimer scheduledTimerWithTimeInterval: 1.0/100.0 target: self selector: #selector(timerUpdating) userInfo: nil repeats: true];
}
-(void)timerUpdating {
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormater = [[NSDateFormatter alloc]init];
[dateFormater setDateFormat:#"mm:ss"];
[dateFormater setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString = [dateFormater stringFromDate:timerDate];
if (self.isPaused == NO){
_timerLabel.text = timeString;
}
}
- (IBAction)pauseAction:(id)sender {
[self pauseTimer:self.timer];
}
- (IBAction)resumeAction:(id)sender {
[self resumeTimer:self.timer];
}
-(void) pauseTimer:(NSTimer *)timer {
self.isPaused = YES;
self.pauseStart = [NSDate date];
self.previousFireDate = [timer fireDate];
[timer setFireDate:[NSDate distantFuture]];
}
-(void) resumeTimer:(NSTimer *)timer {
self.isPaused = NO;
NSDate *currentDate = [NSDate date];
NSTimeInterval pauseTime = [currentDate timeIntervalSinceDate:pauseStart];
NSDate *neededFireDate = [NSDate dateWithTimeInterval:pauseTime sinceDate:previousFireDate];
[timer setFireDate:neededFireDate];
NSLog(#"Fire Date: %#", timer.fireDate);
}
At timerUpdating you set NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];. This will not take into account if the user paused the timer or not.
To correct this behavior you could do something like:
In .h (set a member variable):
NSTimeInterval pausedTime;
In .m (3 lines edited)
- (void)viewDidLoad {
[super viewDidLoad];
[self setUp];
self.isPaused = NO;
pausedTime = 0; //edit
}
- (void) setUp {
startDate = [NSDate date];
_timer = [NSTimer scheduledTimerWithTimeInterval: 1.0/100.0 target: self selector: #selector(timerUpdating) userInfo: nil repeats: true];
}
-(void)timerUpdating {
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate] - pauseTime;//edit
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormater = [[NSDateFormatter alloc]init];
[dateFormater setDateFormat:#"mm:ss"];
[dateFormater setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString = [dateFormater stringFromDate:timerDate];
if (self.isPaused == NO){
_timerLabel.text = timeString;
}
}
- (IBAction)pauseAction:(id)sender {
[self pauseTimer:self.timer];
}
- (IBAction)resumeAction:(id)sender {
[self resumeTimer:self.timer];
}
-(void) pauseTimer:(NSTimer *)timer {
self.isPaused = YES;
self.pauseStart = [NSDate date];
self.previousFireDate = [timer fireDate];
[timer setFireDate:[NSDate distantFuture]];
}
-(void) resumeTimer:(NSTimer *)timer {
self.isPaused = NO;
NSDate *currentDate = [NSDate date];
NSTimeInterval pauseTime = [currentDate timeIntervalSinceDate:pauseStart];
pausedTime += pauseTime;//edit
NSDate *neededFireDate = [NSDate dateWithTimeInterval:pauseTime sinceDate:previousFireDate];
[timer setFireDate:neededFireDate];
NSLog(#"Fire Date: %#", timer.fireDate);
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
i have a view controller in that i want to display time in reverse order.my default time is 00:59:59? i want output like this (00:58:00,00:57:00,00:56:00,00:30:00)?
int currentTimeInSeconds;
NSTimer *myTimer;
if (!timeLabel)
{
timeLabel =0;
}
if (!myTimer)
{
myTimer = [self createTimer];
}
-(NSTimer *)createTimer
{
return [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerTicked) userInfo:nil repeats:YES];
}
-(void)timerTicked
{
if (currentTimeInSeconds == 0)
{
[myTimer invalidate];
currentTimeInSeconds = 60;
timeLabel.text = [self formattedTime:currentTimeInSeconds];
}
else
{
currentTimeInSeconds--;
self.timeLabel.text = [self formattedTime:currentTimeInSeconds];
}
}
-(NSString *)formattedTime:(int)totalSeconds
{
int seconds = totalSeconds%60;
int minutes = (totalSeconds/60)%60;
int hours = totalSeconds/3600;
return [NSString stringWithFormat:#" %02d:%02d:%02d",hours,minutes,seconds];
}
- (IBAction)btnStart:(id)sender {
timet=[self.txtTime.text integerValue];
self.lblTime.text=[NSString stringWithFormat:#"%lu", (unsigned long)timet];
[NSTimer scheduledTimerWithTimeInterval:timet
target:self
selector:#selector(targetMethod)
userInfo:nil
repeats:NO];
[self time];
}
-(void)time
{
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(targetMethod2)
userInfo:nil
repeats:NO];
}
-(void)targetMethod
{
NSLog(#"STOP");
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Stop" message:#"Time is over" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];//, nil
[alert show];
}
-(void)targetMethod2
{
if(timet!=0)
{
timet-=1;
NSLog(#"%lu",(unsigned long)timet);
self.lblTime.text=[NSString stringWithFormat:#"%lu",(unsigned long)timet];
[self time];
}
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0)
{
self.txtTime.text=nil;
self.lblTime.text=nil;
}
}
---------------- Second code ---------------------
#interface ViewController ()
{
UILabel *progress;
NSTimer *timer;
int currMinute;
int currSeconds;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
progress=[[UILabel alloc] initWithFrame:CGRectMake(80, 15, 100, 50)];
progress.textColor=[UIColor redColor];
[progress setText:#"Time : 3:00"];
progress.backgroundColor=[UIColor clearColor];
[self.view addSubview:progress];
currMinute=3;
currSeconds=00;
[self start];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)start
{
timer=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerFired) userInfo:nil repeats:YES];
}
-(void)timerFired
{
if((currMinute>0 || currSeconds>=0) && currMinute>=0)
{
if(currSeconds==0)
{
currMinute-=1;
currSeconds=59;
}
else if(currSeconds>0)
{
currSeconds-=1;
}
if(currMinute>-1)
[progress setText:[NSString stringWithFormat:#"%#%d%#%02d",#"Time : ",currMinute,#":",currSeconds]];
}
else
{
[timer invalidate];
}
}
- (IBAction)startCountdown:(id)sender {
//Set up a timer that calls the updateTime method every second to update the label
NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateCounterLabel)
userInfo:nil
repeats:YES];
}
Every 1 Sec call following function.
-(void)timerTicked
{
NSString *dateString = #"12-12-2015";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormatter dateFromString:dateString];
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *componentsHours = [calendar components:NSHourCalendarUnit fromDate:now];
NSDateComponents *componentMint = [calendar components:NSMinuteCalendarUnit fromDate:now];
NSDateComponents *componentSec = [calendar components:NSSecondCalendarUnit fromDate:now];
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *componentsDaysDiff = [gregorianCalendar components:NSDayCalendarUnit
fromDate:now
toDate:dateFromString
options:0];
long day = (long)componentsDaysDiff.day;
long hours = (long)(24-componentsHours.hour);
long minutes = (long)(60-componentMint.minute);
long sec = (long)(60-componentSec.second);
NSString *strForday = [NSString stringWithFormat:#"%02ld",day];
NSString *strForhours = [NSString stringWithFormat:#"%02ld",hours];
NSString *strForminutes = [NSString stringWithFormat:#"%02ld",minutes];
NSString *strForsec = [NSString stringWithFormat:#"%02ld",sec];
NSLog(#"%# %# %# %# ",strForday,strForhours,strForminutes,strForsec);
if (day == 0 && hours == 0 && minutes == 0 && sec == 0) {
[myTimer invalidate];
}
}
I've looked at the other pause/resume timer questions but couldn't figure out how to fix my problem. I just have a simple timer label and two buttons, a start and a stop button. Let me know if you need any more info on my project to help answer my question. Can anyone see where I'm going wrong?
- (void)updateTimer
{
// Create date from the elapsed time
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:self.startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
// Create a date formatter
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm:ss"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
// Format the elapsed time and set it to the label
NSString *timeString = [dateFormatter stringFromDate:timerDate];
self.stopwatchLabel.text = timeString;
}
- (void)updateResumeTimer
{
// Format the elapsed time and set it to the label
NSString *timeString = [dateFormat stringFromDate:dateFor];
self.stopwatchLabel.text = timeString;
}
- (IBAction)onStartPressed:(id)sender {
NSString *isItEqual = self.stopwatchLabel.text;
if ([isItEqual isEqualToString:#"00:00:00"]) {
self.startDate = [NSDate date];
// Create the stop watch timer that fires every 10 ms
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
}
else {
// Create the stop watch timer that fires every 10 ms
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0
target:self
selector:#selector(updateResumeTimer)
userInfo:nil
repeats:YES];
}
}
- (IBAction)onStopPressed:(id)sender {
resumeText = self.stopwatchLabel.text;
NSLog(#"Timer is %#", resumeText);
dateFormat=[[NSDateFormatter alloc]init];
[dateFormat setDateFormat:#"HH:mm:ss"];
dateFor=[dateFormat dateFromString:resumeText];
[dateFormat setDateFormat:#"HH:mm:ss"];
[self.stopWatchTimer invalidate];
self.stopWatchTimer = nil;
[self updateTimer];
}
You will need to add a property
#property (assign, nonatomic) NSTimeInterval previousTimeInterval;
Just copy the below lines of code and it should work.
- (void)updateTimer
{
// Create date from the elapsed time
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:self.startDate];
timeInterval += self.previousTimeInterval;
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
self.dateFor = timerDate;
// Create a date formatter
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm:ss"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
// Format the elapsed time and set it to the label
NSString *timeString = [dateFormatter stringFromDate:timerDate];
self.stopwatchLabel.text = timeString;
}
- (IBAction)onStartPressed:(id)sender {
self.startDate = [NSDate date];
// Create the stop watch timer that fires every 10 ms
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
//Disable start button and enable stop
self.startButton.enabled = NO;
self.stopButton.enabled = YES;
}
- (IBAction)onStopPressed:(id)sender
{
[self.stopWatchTimer invalidate];
self.stopWatchTimer = nil;
self.previousTimeInterval = [self.dateFor timeIntervalSince1970];
// enable start button and disable stop button
self.startButton.enabled = YES;
self.stopButton.enabled = NO;
}
I am making a basic stopwatch, however, each time I start the timer, click stop, and start again wanting to continue my timer, the clock restarts at 0. I'm not quite sure what to do as I just picked up obj-c/Xcode.
#import "StopwatchViewController.h"
bool stopPressed = false;
bool startPressed = false;
int startsPressed = 0;
NSTimeInterval totalTimeInterval;
#interface StopwatchViewController ()
#property (strong, nonatomic) NSTimer *stopWatchTimer; // Store the timer that fires after a certain time
#property (strong, nonatomic) NSDate *startDate; // Stores the date of the click on the start button
#end
#implementation StopwatchViewController
- (void)updateTimer
{
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate: self.startDate];
totalTimeInterval = timeInterval;
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:totalTimeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat: #"HH:mm:ss.SSS"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString = [dateFormatter stringFromDate:timerDate];
self.stopwatchLabel.text = timeString;
}
- (IBAction)onStartPressed:(id)sender
{
if(startsPressed < 1) {
if(startPressed) return;
startPressed = true;
stopPressed =false;
self.startDate = [NSDate date];
//create the stop watch timer that fires every 100ms
self.stopWatchTimer =
[NSTimer scheduledTimerWithTimeInterval:1.0/100.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
} else {
startPressed = true;
stopPressed = false;
}
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)onStopPressed:(id)sender {
if(stopPressed) return;
stopPressed = true;
startPressed = false;
[self.stopWatchTimer invalidate];
self.stopWatchTimer = nil;
[self updateTimer];
}
- (IBAction)onResetPressed:(id)sender {
if(stopPressed == false) return;
self.stopWatchTimer = 0;
NSString *timeString = #"00:00:00.000";
self.stopwatchLabel.text = timeString;
}
#end
I am currently at this point where my start
#import "StopwatchViewController.h"
bool stopPressed = false;
bool startPressed = false;
int startsPressed = 0;
NSTimeInterval totalTimeInterval;
#interface StopwatchViewController ()
#property (strong, nonatomic) NSTimer *stopWatchTimer; // Store the timer that fires after a certain time
#property (strong, nonatomic) NSDate *startDate; // Stores the date of the click on the start button
#property (nonatomic, strong) NSDate *pauseDate;
#end
#implementation StopwatchViewController
- (void)updateTimer
{
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate: self.startDate];
totalTimeInterval = timeInterval;
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:totalTimeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat: #"HH:mm:ss.SSS"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString = [dateFormatter stringFromDate:timerDate];
self.stopwatchLabel.text = timeString;
}
- (IBAction)onStartPressed:(id)sender
{
// if(startsPressed < 1) {
// if(startPressed) return;
// startPressed = true;
// stopPressed =false;
// self.startDate = [NSDate date];
//
// //create the stop watch timer that fires every 100ms
// self.stopWatchTimer =
// [NSTimer scheduledTimerWithTimeInterval:1.0/100.0
// target:self
// selector:#selector(updateTimer)
// userInfo:nil
// repeats:YES];
// } else {
//
// startPressed = true;
// stopPressed = false;
//
// }
if(startsPressed < 1) {
if( ! _startDate) {
self.startDate = [NSDate date];
}
else {
if(_pauseDate) {
NSTimeInterval startTime = _startDate.timeIntervalSince1970;
NSTimeInterval pauseTime = _startDate.timeIntervalSince1970;
// the actual elapsed time before we paused
NSTimeInterval elapsedTime = pauseTime - startTime;
// set a new start time to match our elapsed time.
NSTimeInterval currentTime = [NSDate date].timeIntervalSince1970;
NSTimeInterval newStartTime = currentTime - elapsedTime;
_startDate = [NSDate dateWithTimeIntervalSince1970:newStartTime];
_pauseDate = nil;
}
}
}
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)onStopPressed:(id)sender {
if(stopPressed) return;
_pauseDate = [NSDate date];
stopPressed = true;
startPressed = false;
[self.stopWatchTimer invalidate];
self.stopWatchTimer = nil;
[self updateTimer];
}
- (IBAction)onResetPressed:(id)sender {
if(stopPressed == false) return;
_startDate = nil;
_pauseDate = nil;
self.stopWatchTimer = 0;
NSString *timeString = #"00:00:00.000";
self.stopwatchLabel.text = timeString;
}
#end
Every time you hit "start", this code gets run:
self.startDate = [NSDate date];
This resets the start time you are using. Move that out somewhere so that it only happens once instead of on every time you start the timer and I think the result will be closer to what you want. Perhaps you can just store an extra BOOL that gets switched the first time the timer is started.
Edit:
Very good point brought up by Stonz2 that I overlooked. Doing it this way will cause the time to skip once you start it back up. In order to fix this you will need to store a separate NSDate when you stop the timer, to represent the "paused" time. Then, when you are starting the timer back up again, you will need to add the "paused" time to the "start" time so that the continuation is fluid.
Edit2:
I threw this into a project and here is some working code.
I added an extra property:
#property (nonatomic, strong) NSDate *pauseDate;
In onStopPressed:, I added this to initialize the pause time:
_pauseDate = [NSDate date];
Then, in onStartPressed:, I added the following code to ensure a single initialization of the startDate and to do the math to get the elapsed time after pausing:
// if we have a start date, don't initialize again
if(! _startDate)
{
self.startDate = [NSDate date];
}
else
{
if(_pauseDate)
{
NSTimeInterval startTime = _startDate.timeIntervalSince1970;
NSTimeInterval pauseTime = _pauseDate.timeIntervalSince1970;
// The actual elapsed time before we paused.
NSTimeInterval elapsedTime = pauseTime - startTime;
// Set a new start time to match our elapsed time.
NSTimeInterval currentTime = [NSDate date].timeIntervalSince1970;
NSTimeInterval newStartTime = currentTime - elapsedTime;
_startDate = [NSDate dateWithTimeIntervalSince1970:newStartTime];
_pauseDate = nil;
}
}
Also, in order to make your reset work correctly, in onResetPressed: you will need to add:
_startDate = nil;
_pauseDate = nil;
Just tested this and it works like a champ.
Edit3: full method as per comment thread
- (IBAction)onStartPressed:(id)sender
{
if(startsPressed < 1) {
if(startPressed) return;
startPressed = true;
stopPressed =false;
if(! _startDate)
{
self.startDate = [NSDate date];
}
else
{
if(_pauseDate)
{
NSTimeInterval startTime = _startDate.timeIntervalSince1970;
NSTimeInterval pauseTime = _pauseDate.timeIntervalSince1970;
NSTimeInterval elapsedTime = pauseTime - startTime;
NSTimeInterval currentTime = [NSDate date].timeIntervalSince1970;
NSTimeInterval newStartTime = currentTime - elapsedTime;
_startDate = [NSDate dateWithTimeIntervalSince1970:newStartTime];
_pauseDate = nil;
}
}
//create the stop watch timer that fires every 100ms
self.stopWatchTimer =
[NSTimer scheduledTimerWithTimeInterval:1.0/100.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
} else {
startPressed = true;
stopPressed = false;
}
}
It is because you reset self.startDate in the onStartPressed method. Do this only in viewDidLoad: and in onResetPressed:
I have an NSTimer which I pause and resume with the following methods respectively:
-(void) pauseTimer:(NSTimer *)timer {
self.scene.paused = YES;
pauseStart = [NSDate date];
previousFireDate = [timer fireDate];
[timer setFireDate:[NSDate distantFuture]];
}
-(void) resumeTimer:(NSTimer *)timer {
self.scene.paused = NO;
NSDate *currentDate = [NSDate date];
NSTimeInterval pauseTime = [currentDate timeIntervalSinceDate:pauseStart];
NSDate *neededFireDate = [NSDate dateWithTimeInterval:pauseTime sinceDate:previousFireDate];
[timer setFireDate:neededFireDate];
NSLog(#"Fire Date: %#", timer.fireDate); //returning null
}
It is not properly resetting the fire date because when I check timer.fireDate, it says null. All we want is for these methods to pause the timer and resume the timer where it left off when the resume method is called. Any help is greatly appreciated.
My solution differs from yours in one major thing. I recreate a timer when it resumes. Here is how I do it and it's been working quite well:
#property (nonatomic, strong) NSTimer *timer;
#property (nonatomic, assign) NSTimeInterval elapsedTime;
#property (nonatomic, strong) NSDate *startDate;
- (void)startTimer
{
NSTimeInterval timeInterval = 20.0f;
// Create a timer. Adjust the elapsed time.
_timer = [NSTimer scheduledTimerWithTimeInterval:(timeInterval - _elapsedTime)
target:self
selector:#selector(timerFireMethod:)
userInfo:nil
repeats:YES];
// Save the start date.
_startDate = [NSDate date];
}
- (void)timerFireMethod:(NSTimer *)theTimer
{
// Clean.
[_timer invalidate];
_timer = nil;
_elapsedTime = 0.0;
[self startTimer];
// Additional handling.
}
- (void)pauseTimer
{
// Clean.
[_timer invalidate];
_timer = nil;
// Save the elapsed time.
_elapsedTime = [[NSDate date] timeIntervalSinceDate:_startDate];
}
Hope it helps.
I have this NSTimer that I want it to stop after 45 minutes, but it won't stop.
What am I doing wrong?
TIMER_COUNT = 45
HOURS_IN_HOURS = 60
HOURS_IN_DAY = 24
- (void)start
{
self.timerCountdown = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateCountdown) userInfo:nil repeats: YES];
}
- (void)stop
{
[self.timerCountdown invalidate];
self.timerCountdown = nil;
}
- (void)updateCountdown
{
NSDate *currentDate = [NSDate date];
NSDate *finalTime = [currentDate dateByAddingTimeInterval:(TIMER_COUNT * HOURS_IN_HOUR)];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *componentsHours = [calendar components:NSHourCalendarUnit fromDate:currentDate];
NSDateComponents *componentMinuts = [calendar components:NSMinuteCalendarUnit fromDate:currentDate];
NSDateComponents *componentSeconds = [calendar components:NSSecondCalendarUnit fromDate:currentDate];
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *componentsDaysDiff = [gregorianCalendar components:NSDayCalendarUnit
fromDate:currentDate
toDate:finalTime
options:0];
NSLog(#"%20d Days, %02d Hours, %02d Minutes, %02d Seconds.", componentsDaysDiff.day, HOURS_IN_DAY - componentsHours.hour, HOURS_IN_HOUR - componentMinuts.minute, HOURS_IN_HOUR - componentSeconds.second);
if ([currentDate compare:finalTime] == NSOrderedSame)
{
NSLog(#"Done.");
[self stop];
}
}
Thanks in advance.
Because your currentDate will keep being set every time your timer ticks. [NSDate date] will set currentDate to the current time every time the updateCountdown method runs. Therefore will finalTime always be 45 minutes ahead of currentDate. You should create a startDate property and set it in the start method instead:
- (void)start
{
self.timerCountdown = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateCountdown) userInfo:nil repeats: YES];
self.startDate = [NSDate date];
}
Then check on the property in the updateCountdown method:
if ([self.startDate compare:finalTime] == NSOrderedSame)
{
NSLog(#"Done.");
[self stop];
}
Alternatively you can use an integer with the number of ticks you are expecting and then substract one from the integer everytime the timer ticks.
Something like this:
- (void)start
{
self.timerCountdown = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateCountdown) userInfo:nil repeats:YES];
self.countdown = TIMER_COUNT * HOURS_IN_HOUR;
}
- (void)updateCountdown
{
self.countdown--;
//your code
if (self.countdown == 0)
{
NSLog(#"Done.");
[self stop];
}
}
- (void)start {
NSString *startTime = [NSDate date];
NSDateComponents *durationComponents = [[[NSDateComponents alloc] init] autorelease];
durationComponents.minutes = 45;
NSCalendar *gregorianCalendar = [NSCalendar currentCalendar];
self.endTime = [calendar dateByAddingComponents:durationComponents
toDate:startTime
options:0];
self.timerCountdown = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateCountdown)
userInfo:nil
repeats:YES];
}
- (void)stop {
[self.timerCountdown invalidate];
self.timerCountdown = nil;
}
- (void)updateCountdown {
NSDate *currentTime = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *currentTimeComponents = [calendar components:(NSHourCalendarUnit | NSMinuteCalendarUnit |NSSecondCalendarUnit)
fromDate:currentTime];
if ([currentTime compare:self.endTime] == NSOrderedDescending) {
[self stop];
}
}
You don't need the startDate property.
And you should not check dates for equality. That is very unlikely to happen.
Use that comparison:
if ([finalTime compare:[NSDate date]] == NSOrderedAscending)
{
NSLog(#"Done.");
[self.timerCountdown invalidate];
[self stop];
}
This means that finalTime is earlier in time than current time.