Add a Running Countup Display Timer to an iOS App, Like the Clock Stopwatch

Add a running countup display timer to an iOS app, like the Clock stopwatch?

Almost what @terry lewis suggested but with an algorithm tweak:

1) schedule a timer

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTick:) userInfo:nil repeats:YES];

2) when the timer fires, get the current time (that's the tweak, don't count ticks because if there is wobble in the timer, tick counting will accumulate the error), then update the UI. Also, NSDateFormatter is a simpler and more versatile way to format time for display.

- (void)timerTick:(NSTimer *)timer {
NSDate *now = [NSDate date];

static NSDateFormatter *dateFormatter;
if (!dateFormatter) {
dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"h:mm:ss a"; // very simple format "8:47:22 AM"
}
self.myTimerLabel.text = [dateFormatter stringFromDate:now];
}

Doing a chrono for an iOS app

For this kind of "refreshing stuff", you should use a NSTimer:

//initialize this in your viewDidload
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(refreshLabel)
userInfo:nil
repeats:Yes];

Then, in implement in your controller the method passed in the selector parameter above:

-(void)refreshLabel
{
//logic here: incrementing some counter and setting in your label
}

If you want a smaller piece of time, just change it in scheduledTimerWithTimeInterval parameter.

This, of course, is just how you would set your label (assuming you have an IBOutlet to one) to be refreshed every second. You still would have to create chrono's logic (incrementing some instance variable, creating some logic to split minutes / seconds, or using NSDate methods). If you still want help with other things, please let us know.

Josh Caswell's links in comments will be a lot helpful to you.

If you with more information about the NSTimer, please read the Apple's documentation: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Timers/Articles/usingTimers.html#//apple_ref/doc/uid/20000807-CJBJCBDE

Timer since a user is logged on in Xcode

You can start and stop timer in app delegate methods like

application:willFinishLaunchingWithOptions,
application:didFinishLaunchingWithOptions,
applicationDidBecomeActive:
applicationWillResignActive:
applicationDidEnterBackground:
applicationWillEnterForeground:
applicationWillTerminate:

Refer to the following document for more info:

http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html

Display StopWatch Timer animated like the petrol pump meter using NSTimer

You need to manually scroll tableView instead of scrollToRowAtIndexPath because this animation uses its own timer interval and its very difficult or we can say impossible to change its time interval.

So, I am Implementing an API for such kind of problems and made a demo app for you with smooth scrolling as you want.

You need to use an outer timer that fires every 1 second and an internal timer that will fire every 0.03 sec as my tableRow Height is 30 I calculated internal timer interval as :---

Move 30 pixels for 1 sec , then
Move 1 pixel for 0.33 sec inside internal timer.

The Internal timer will invalidate and fire every 1 second as initialized within outer timer.

And internal timer will perform the movement of cell.

dial4 is a tableView

Have a look at my code.

#define rowHeight 30

-(void)startCounter
{
outertimer=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(snapCell) userInfo:nil repeats:YES];
}

-(void)stopCounter
{
[outertimer invalidate];
}

-(void)snapCell
{
NSLog(@"Initialize Internal timer %i",secLsb);
secLsb++;

if (secLsb==10) {
[dial4 setContentOffset:CGPointMake(0, 0) animated:NO];
secLsb=0;
NSLog(@"dial content offset y is %f",dial4.contentOffset.y);
}

[internaltimer invalidate];
internaltimer=[NSTimer scheduledTimerWithTimeInterval:0.03
target:self
selector:@selector(automaticScroll)
userInfo:nil
repeats:YES];
}

-(void)automaticScroll
{
NSLog(@"val is & y ======== %f",dial4.contentOffset.y);

[dial4 setContentOffset:CGPointMake(dial4.contentOffset.x,dial4.contentOffset.y+1) animated:NO];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return rowHeight;
}

Have a look at Time Counter

Format realtime stopwatch timer to the hundredth using Swift

For rapid UI updates you should use a CADisplayLink. Anything faster than the display refresh rate is a waste of processing power since it physically cannot be displayed. It also provides a timestamp of the previous frame so you can try to predict when the next frame will be.

You're calculating CACurrentMediaTime() - timerStarted + elapsedTime multiple times. I would recommend doing it only once and saving it in a local variable.

Consider using NSDateComponentsFormatter. Try to reuse one instance of the formatter rather than creating a new one each time (which is usually the most expensive part). Overall, the less string manipulation you can do, the better.

You can check CACurrentMediaTime at the beginning and end of your display method to see how long it takes. Ideally it should be much less than 16.6ms. Keep an eye on the CPU usage (and general power consumption) in the Xcode debug navigator.

Correct way to display current date/time in iOS app and keep it up to date

The recursive method is not a great idea.

Use NSTimer approach. Create the repeating timer in viewDidAppear and invalidate the timer in viewDidDisappear (to avoid retain cycle, a.k.a. strong reference cycle). For example, assuming you have a timer property:

@property (nonatomic, strong) NSTimer *timer;

You would then schedule and invalidate the timer as follows:

- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];

self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(handleTimer:) userInfo:nil repeats:YES];
}

- (void)viewDidDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];

[self.timer invalidate];
self.timer = nil;
}

- (void)handleTimer:(NSTimer *)timer
{
// update your label here
}

If you don't release and/or invalidate the timer, it will maintain a strong reference to your controller and you can end up with a strong reference cycle. And you cannot resolve this strong reference cycle in dealloc (because dealloc is not called until the controller has no more strong references; the presence of a repeating NSTimer that has not been invalidated will prevent dealloc from ever getting called), which is why we do it in viewDidDisappear.

iOS prevent date/time update?

You are correct in thinking that CFAbsoluteTime and its derivatives (NSDate dateand so on) are potentially skewed by network updates on 'real' time. Add that to the fact that NSTimer has an accuracy of 50-100ms and you have a timer that is not suited to the most critical of time-sensitive operations.

The answer to this problem seems to be CACurrentMediaTime.
It is a member of the Core Animation group, but there shouldn't be any problem integrating it into non-animation based applications.

CACurrentMediaTime is a wrapper of mach_absolute_time() and makes sense of the "mach absolute time unit," which from my understanding is no fun to tinker with. mach_absolute_time() is calculated by running a non-network synced timer since the device was last booted.

There is relatively little information on CACurrentMediaTime but here are some sources and further reading:

  • Apple's sparse documentation of CACurrentMediaTime
  • Stack Overflow - NSTimer vs CACurrentMediaTime()
  • http://bendodsonapps.com/weblog/2013/01/29/ca-current-media-time/
  • http://blog.spacemanlabs.com/2011/09/all-in-the-timing-keeping-track-of-time-passed-on-ios/
  • http://forum.sparrow-framework.org/topic/accurate-timer

Note: If you do use CACurrentMediaTime, make sure you include and link the QuartzCore.framework

I want to show current time on a label with time format hh:mm:ss

You should use NSTimer :

- (void)viewDidLoad
{
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(timeNotify)
userInfo:nil
repeats:YES];
}

- (void) timeNotify
{
NSDate *currentTime = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"hh:mm:ss"];
NSString *resultString = [dateFormatter stringFromDate: currentTime];
_timeLbl.text = resultString;
}


Related Topics



Leave a reply



Submit