I am new to NSTimer in iPhone. i made a stop watch. now i want to pause time in between
and also want to do resume pause. my code is given bellow.
How can I pause time?
How can i resume from where the time is stop?
Start Time:
startDate = [[NSDate date]retain];
stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
Stop Time:
[stopWatchTimer invalidate];
stopWatchTimer = nil;
[self updateTimer];
Update Time:
(void)updateTimer
{
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"mm:ss"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString=[dateFormatter stringFromDate:timerDate];
stopWatchLabel.text = timeString;
[dateFormatter release];
}
You can use NSTimeInterval instead of timer. I have a functional code to pause and stop the timer.
#interface PerformBenchmarksViewController () {
int currMinute;
int currSecond;
int currHour;
int mins;
NSDate *startDate;
NSTimeInterval secondsAlreadyRun;
}
#end
- (void)viewDidLoad
{
[super viewDidLoad];
running = false;
}
- (IBAction)StartTimer:(id)sender {
if(running == false) {
//start timer
running = true;
startDate = [[NSDate alloc] init];
startTime = [NSDate timeIntervalSinceReferenceDate];
[sender setTitle:#"Pause" forState:UIControlStateNormal];
[self updateTime];
}
else {
//pause timer
secondsAlreadyRun += [[NSDate date] timeIntervalSinceDate:startDate];
startDate = [[NSDate alloc] init];
[sender setTitle:#"Start" forState:UIControlStateNormal];
running = false;
}
}
- (void)updateTime {
if(running == false) return;
//calculate elapsed time
NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval elapsed = secondsAlreadyRun + currentTime - startTime;
// extract out the minutes, seconds, and hours of seconds from elapsed time:
int hours = (int)(mins / 60.0);
elapsed -= hours * 60;
mins = (int)(elapsed / 60.0);
elapsed -= mins * 60;
int secs = (int) (elapsed);
//update our lable using the format of 00:00:00
timerLabel.text = [NSString stringWithFormat:#"%02u:%02u:%02u", hours, mins, secs];
//call uptadeTime again after 1 second
[self performSelector:#selector(updateTime) withObject:self afterDelay:1];
}
Hope this will help. Thanks
I created some extra variables to help keep track on the elapsed time:
BOOL watchStart;
NSTimeInterval pauseTimeInterval;
I set watchStart = NO and pauseTimeInterval = 0.0.
I used watchStart to check if its a start or pause condition (for my IBAction), and in updateTimer, I set the timeInterval to pauseTimeInterval.
The crucial part of the code is:
_startDate = [_startDate dateByAddingTimeInterval:((-1)*(_pauseTimeInterval))]
That line will add the extra timeInterval to the startDate for calculation of the time that was paused. It's kind of like "stepping back" in time to add in the interval that was previously recorded.
-(void) updateTimer {
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:_startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"mm:ss.S"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString = [dateFormatter stringFromDate:timerDate];
_stopWatchLabel.text = timeString;
_pauseTimeInterval = timeInterval;
}
-(IBAction)btnStartPause:(id)sender {
if(_watchStart == NO) {
_watchStart = YES;
_startDate = [NSDate date];
_startDate = [_startDate dateByAddingTimeInterval:((-1)*(_pauseTimeInterval))];
_stopWatchTime = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0 target:self selector:#selector(updateTimer) userInfo:nil repeats:YES];
}
else {
_watchStart = NO;
[_stopWatchTime invalidate];
_stopWatchTime = nil;
[self updateTimer];
}
NSTimer does not have pause or resume methods. You can make 2 types of timers, one that implements only once and the second, that repeats. Example:
Creates a timer that will enter callback myMethod each second.
NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(myMethod:)
userInfo:nil
repeats:YES];
You probably will choose this one for your purpose where in your class you should maintain some
BOOL pausevariable and in the callback myMethod do the following:
- (void) myMethod:(NSTimer *) aTimer
{
if (!pause) {
// do something
// update your GUI
}
}
where you update pause in your code. To stop the timer and release memory, call
[myTimer invalidate];
hope this helped.
Small correction for the above example:
_startDate = [_startDate dateByAddingTimeInterval:((-1)*(_pauseTimeInterval))];
Add retain # the end :
_startDate = [[_startDate dateByAddingTimeInterval:((-1)*(_pauseTimeInterval))]retain];
This will make things better :-)
-(void)startStopwatch
{
//initialize the timer HUD
[self setSeconds:second];
// [self.hud.stopwatch setSeconds:_secondsLeft];
//schedule a new timer
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(tick:)
userInfo:nil
repeats:YES];
}
-(void)pause{
[_timer invalidate];
}
-(void)resume {
[_timer isValid];
}
using this code we can pause and resume the timer
Friends i was successful in implementing pause and resume function to iOs timer app, the code is as follows
- (IBAction)pauseT:(id)sender {
se = sec;
mi = min;
ho = hour;
[timer invalidate];
}
- (IBAction)resumeT:(id)sender {
sec = se;
min = mi;
hour = ho;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countDown) userInfo:nil repeats:YES];
}
Hope this works for you guys..
Related
I know how to use NSDate to get the time and display it inside UILabel.
i need to display the date + hours and minutes.
any idea how can i keep it updated without busy-waiting?
Thanks!
Use NSTimer to update time on the label
- (void)viewDidLoad
{
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(updateTime) userInfo:nil repeats:YES];
}
-(void)updateTime
{
NSDate *date= [NSDate date];
NSDateFormatter *formatter1 = [[NSDateFormatter alloc]init]; //for hour and minute
formatter1.dateFormat = #"hh:mm a";// use any format
clockLabel.text = [formatter1 stringFromDate:date];
[formatter1 release];
}
As your comments said , if you want when minutes changes you change the label.text
you should do like this :
1st: get the current time:
NSDate *date = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [calendar components:NSHourCalendarUnit fromDate:date];
and set the label.text = CURRENTHOUR_AND_YOURMINNUTS;
and then refresh the label next minute,like this :
the first , you can check after 60 - nowSeconds
[self performSelector:#selector(refreshLabel) withObject:nil afterDelay:(60 - dateComponents.minute)];
- (void)refreshLabel
{
//refresh the label.text on the main thread
dispatch_async(dispatch_get_main_queue(),^{ label.text = CURRENT_HOUR_AND_MINUTES; });
// check every 60s
[self performSelector:#selector(refreshLabel) withObject:nil afterDelay:60];
}
It will check every minute , so the effecent is more than answers above.
When refreshLabel invocated , it means the minutes changed
You can use the NSTimer to periodically get the current time.
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(timerFired:) userInfo:nil repeats:YES];
- (void)timerFired:(NSTimer*)theTimer{
//you can update the UILabel here.
}
You can use NSTimer , but , given the above methods , the UILabel won't update on touch Events as the main thread will be busy tracking it.You need to add it to mainRunLOOP
NSTimer* timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:#selector(updateLabelWithDate) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
-(void)updateLabelWithDate
{
//Update your Label
}
You can change the time interval(rate at which you want Updation).
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I want to display count down timer. I have the start date and end date. I need to display the remaining time like
days : hours : minutes : seconds
How can I do this?
you can set coundown like my below code :-
-(void) viewWillAppear:(BOOL)animated
{
timer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target:self selector:#selector(updateCountdown) userInfo:nil repeats: YES];
}
AND
-(void) updateCountdown
{
NSString *dateString = #"14-12-2012";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSDate *dateFromString = [[NSDate alloc] init];
// voila!
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];
lblDaysSetting.text=[NSString stringWithFormat:#"%02d",componentsDaysDiff.day];
lblHouresSetting.text=[NSString stringWithFormat:#"%02d",(24-componentsHours.hour)];
lblMinitSetting.text=[NSString stringWithFormat:#"%02d",(60-componentMint.minute)];
lblSecSetting.text=[NSString stringWithFormat:#"%02d",(60-componentSec.second)];
}
now just set your logic
its code output as my project as bellow::-
this is the code for .h file:
#interface UIMyContoller : UIViewController {
NSTimer *timer;
IBOutlet UILabel *myCounterLabel;
}
#property (nonatomic, retain) UILabel *myCounterLabel;
-(void)updateCounter:(NSTimer *)theTimer;
-(void)countdownTimer;
#end
and here is the code for .m file:
#implementation UIMyController
#synthesize myCounterLabel;
int hours, minutes, seconds;
int secondsLeft;
- (void)viewDidLoad {
[super viewDidLoad];
secondsLeft = 16925;
[self countdownTimer];
}
- (void)updateCounter:(NSTimer *)theTimer {
if(secondsLeft > 0 ){
secondsLeft -- ;
hours = secondsLeft / 3600;
minutes = (secondsLeft % 3600) / 60;
seconds = (secondsLeft %3600) % 60;
myCounterLabel.text = [NSString stringWithFormat:#"%02d:%02d:%02d", hours, minutes, seconds];
}
else{
secondsLeft = 16925;
}
}
-(void)countdownTimer{
secondsLeft = hours = minutes = seconds = 0;
if([timer isValid])
{
[timer release];
}
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
[pool release];
}
hope this helps. happy coding
adrian
I would recommend the below method of getting time components of From Date to To Date.
This method is more elegant than manually decrementing 3 integer variables for hour, minute and seconds because doing so would mean you have to manually check when a second hit 0, you need to manually reset the minute back to 59 and so on. I went down this route once, it wasn't very good.
Also, when you minimize your app, the count down clock will stop. If you were decrementing your count down timer manually using 3 integers (hour, minute and seconds), minimizing your app will cause the count down to screw up.
Since this method auto calculates the difference between two dates, even when the app returns from the background minimized state, it automatically recalculates the remaining time for you without any extra code.
-(void)viewDidLoad
{
// instantiate a calendar object.
gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
countDownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateClock:) userInfo:nil repeats:YES];
[countDownTimer fire];
}
-(void)updateClock:(NSTimer *)timer
{
countDownDateFormatter = [[NSDateFormatter alloc] init];
[countDownDateFormatter setDateFormat:#"hh:mm:ss"];
NSDate *now = [NSDate date];
NSDateComponents *comp = [gregorianCalendar components:NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit
fromDate:now
toDate:countDownEndDate
options:0];
NSString *strTimeRemaining = nil;
// if date have not expired
if([now compare:countDownEndDate] == NSOrderedAscending)
{
strTimeRemaining = [[NSString alloc] initWithFormat:#"%02d:%02d:%02d", [comp hour], [comp minute], [comp second]];
}
else
{
// time has expired, set time to 00:00 and set boolean flag to no
strTimeRemaining = [[NSString alloc] initWithString:#"00:00:00"];
[countDownTimer invalidate];
countDownTimer = nil;
}
lblCountDown.text = strTimeRemaining;
[countDownDateFormatter release];
[strTimeRemaining release];
}
I've been searching internet for a few days till now. I did find some useful information but just want to make things perfect.
I'm trying to write a countdown app which only uses second, my current code is a bit too complex and maybe off the main road. Looking for someone who can straight it up.
- (void)updateTimer{
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"s"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString=[dateFormatter stringFromDate:timerDate];
// where the part change time string back to int
NSString *changeToInt = timeString;
int stringInt = [changeToInt integerValue];
// loop for count down numbers
if ((buttValue - stringInt) > 0) {
leftTime = buttValue - stringInt;
[self updateValue];
} else {
leftTime = 0;
[self updateValue];
}
}
2 problems with the code, 1) do I have to go through all the date formatting to get a integer? 2) in the loop I used two variables, I was hoping to take one out and use something like --
I don't understand what you need exactly, but I think that you just want to get the number of seconds from now to a known date. The timeIntervalSinceNow method will give you a NSInteger value that represent the number of seconds from the receiver date until now, which, if the receiver is earlier than now, will be a negative value (otherwise it will be positive).
So, just to be more explicit:
- (void)updateTimer
{
leftTime = MAX(0, -[startDate timeIntervalSinceNow]); //if less than 0 will be forced to 0 -> date reached
[self updateValue];
}
As I said, I'm not sure this is what you want. If it's not, I am sorry.
Good luck!
-(void)initialiseTimer
{
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timeElapsed) userInfo:nil repeats:YES];
startDate = [[NSDate date] retain];
}
-(void)timeElapsed
{
NSLog(#"Seconds elapsed since start date %d", abs([startDate timeIntervalSinceNow]));
}
you can manipulate it to make a count down style app.
Use this code !!
-(IBAction)startAndStop:(id)sender
{
startDate = [[NSDate date]retain];
if([btnStopWatch.titleLabel.text isEqualToString:#"Start"])
{
stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/100.0 target:self selector:#selector(updateTimer) userInfo:nil repeats:YES];
[btnStopWatch setTitle:#"Stop" forState:UIControlStateNormal];
}
else if([btnStopWatch.titleLabel.text isEqualToString:#"Stop"])
{
[stopWatchTimer invalidate];
[btnStopWatch setTitle:#"Start" forState:UIControlStateNormal];
}
}
- (void)updateTimer
{
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm:ss"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
timeString=[dateFormatter stringFromDate:timerDate];
stopWatchLabel.text = timeString;
NSLog(#"Seconds elapsed since start date %d", abs([startDate timeIntervalSinceNow]));
}
Please help. I want to create countdown timer using iphone sdk. I have current time:
NSDate *today = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm"];
NSString *currentTime = [dateFormatter stringFromDate:today];
[dateFormatter release];
and time(s) from database. Eg.: currentTime is 19:18:30, time from database is 19:20:01. So the timer should be set to 0:01:31 and begin the countdown. When reach the 0:00:00, take another time from database (eg: 19:21:00), set up timer (0:00:59) and star countdown again. When reach the 0:00:00, take... The timer should be displayed by UILabel.
Please help. It begins to make me mad. :)
try this. I've just written only required methods for the solution. Don't forget to implement dealloc etc.
CountdownViewController.h
#interface CountdownViewController : UIViewController {
IBOutlet UILabel *clockLabel;
NSDate *databaseDate;
NSTimer *timer;
}
#property(nonatomic, retain) IBOutlet UILabel *clockLabel;
#property(nonatomic, retain) NSDate *databaseDate;
#end
CountdownViewController.m
#implementation CountdownViewController
#synthesize clockLabel;
#synthesize databaseDate;
- (void) showClock {
NSTimeInterval remainingSec = [databaseDate timeIntervalSinceNow];
if (!timer || remainingSec <= 0) {
[timer invalidate];
timer = nil;
// getting time from database
self.databaseDate = [NSDate dateWithTimeIntervalSinceNow:20.0];
remainingSec = [databaseDate timeIntervalSinceNow];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self
selector:#selector(showClock)
userInfo:nil
repeats:YES];
}
NSInteger hours = remainingSec / 3600;
NSInteger remainder = ((NSInteger)remainingSec)% 3600;
NSInteger minutes = remainder / 60;
NSInteger seconds = remainder % 60;
clockLabel.text = [NSString stringWithFormat:#"%02d:%02d:%02d", hours, minutes, seconds];
}
#end
I need the iPhone to recognize the current time (which I can do fine with NSDate) and have it countdown to the next time interval, say every half hour on the half hour. Example: if the current time is 2:12:30 and the interval is every half hour, I want a countdown to start at 17:30 (17 min 30 seconds left) and go to 0.
Code welcome, but also general program design thoughts welcome too. Here's the code I have for starting a countdown and getting the current time:
-(void)updateCounter:(NSTimer *)theTimer {
if(secondsLeft > 0 ){
secondsLeft -- ;
minutes = (secondsLeft % 3600) / 60;
seconds = (secondsLeft % 3600) % 60;
waitingTimeLabel.text = [NSString stringWithFormat:#"%02d:%02d", minutes, seconds];
}
else{
secondsLeft = 10;
}
}
-(void)countdownTimer{
//secondsLeft = minutes = seconds = 0;
if([timer isValid])
{
[timer release];
}
// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
//[pool release];
}
-(NSDate *)getCurrentTime
{
NSDate *now = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"mm:ss";
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
NSLog(#"The Current Time is %#",[dateFormatter stringFromDate:now]);
//[dateFormatter release];
NSString *currentTime = [NSString stringWithFormat:#"%#",[dateFormatter stringFromDate:now]];
currentTimeLabel.text = currentTime;
return now;
}
NSDate *now = [NSDate date];
int interval = 30*60; // half hour
long int nowSeconds = (long int) [now timeIntervalSince1970];
int secondsLeft = interval - (nowSeconds % interval);
NSDate *nextIntervalDate = [NSDate
dateWithTimeIntervalSince1970:nowSeconds+secondsLeft];
NSLog(#"Now is %#", now);
NSLog(#"The next interval point in time is %#", nextIntervalDate);
NSLog(#"That's another %d seconds (or %02d:%02d)",
secondsLeft, secondsLeft/60, secondsLeft%60);