I have a determinate progress bar which looks like the following:
NSInteger progressValue;
NSTimer *timerObject;
- (void)incrementProgressBar {
// Increment the progress bar value by 1
[progressBar incrementBy:1.0];
progressValue++;
[progressBar setDoubleValue:progressValue];
}
And then I call it by:
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(incrementProgressBar) userInfo:nil repeats:YES];
My question: Is it possible to increment the scheduledTimerWithTimeInterval for each iteration?
So for example if the progressValue was 1 then scheduledTimerWithTimeInterval would be 1, but if progressValue was 2 then scheduledTimerWithTimeInterval would be 2, etc.
Basically what I'm trying to do is progressively slow the progress bar down the closer it gets to 100. There's probably some better way or recommendation for doing this, but it's essentially what I'm looking for, thanks.
Use -fireDate:(NSDate*) to set the next date when the NSTimer will fire. For further explanation of the API, go here.
For example, you can achieve that as follows:
NSDate *currentDate = [NSDate date];
NSDate *newDate = [NSDate dateWithTimeInterval:(NSTimeInterval)progressValue sinceDate: currentDate];
timerObject.fireDate = newDate;
Related
I'm working with an app that processes device motion events and updates interface in 5 second increments. I would like to add an indicator to the app that would display the total time the app has been running. It seems that a stopwatch-like counter, like the native iOS Clock app is a reasonable way to count time that the app has been running and display it to the user.
What I'm not sure of is the technical implementation of such a stopwatch. Here's what I'm thinking:
if I know how long between interface updates, I can add up seconds between events and keep a count of seconds as a local variable. Alternatively, a 0.5 second interval scheduled timer can provide the count.
If I know the start date of the app, I can convert the local variable to date for each interface update using [[NSDate dateWithTimeInterval:(NSTimeInterval) sinceDate:(NSDate *)]
I can use a NSDateFormatter with a short time style to convert the updated date to a string using stringFromDate method
The resulting string can be assigned to a label in the interface.
The result is that the stopwatch is updated for each "tick" of the app.
It appears to me that this implementation is a bit too heavy and is not quite as fluid as the stopwatch app. Is there a better, more interactive way to count up time that the app has been running? Maybe there's something already provided by iOS for this purpose?
If you look in the iAd sample code from Apple in the basic banner project they have a simple timer:
NSTimer *_timer;
_timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(timerTick:) userInfo:nil repeats:YES];
and the the method they have
- (void)timerTick:(NSTimer *)timer
{
// Timers are not guaranteed to tick at the nominal rate specified, so this isn't technically accurate.
// However, this is just an example to demonstrate how to stop some ongoing activity, so we can live with that inaccuracy.
_ticks += 0.1;
double seconds = fmod(_ticks, 60.0);
double minutes = fmod(trunc(_ticks / 60.0), 60.0);
double hours = trunc(_ticks / 3600.0);
self.timerLabel.text = [NSString stringWithFormat:#"%02.0f:%02.0f:%04.1f", hours, minutes, seconds];
}
It just runs from start up, pretty basic.
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];
}
This calls my selector repeatedly each 60 seconds as desired:
autoDeleteTimer = [NSTimer scheduledTimerWithTimeInterval:60 target:[SimpleDB class] selector:#selector(autoDelete:) userInfo:nil repeats:YES];
This next line doesn't call it at all. Not initially nor after 60 seconds:
autoDeleteTimer = [[NSTimer alloc] initWithFireDate: [NSDate dateWithTimeIntervalSinceNow:1] interval:60 target:[SimpleDB class] selector:#selector(autoDelete:) userInfo:nil repeats:YES];
Can anyone explain why? Thanks.
You need to add the second timer to the main loop:
[[NSRunLoop mainRunLoop] addTimer: autoDeleteTimer forMode:NSDefaultRunLoopMode];
From the documentation of the method:
- (id)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats
Return Value:
The receiver, initialized such that, when added to a run loop, it will
fire at date and then, if repeats is YES, every seconds after that.
You must add the new timer to a run loop, using addTimer:forMode:.
Upon firing, the timer sends the message aSelector to target. (If the
timer is configured to repeat, there is no need to subsequently re-add
the timer to the run loop.)
NSTimer Apple Doc
I write a simple application for mac osx that works with system time to calculate some data, i want to run an specific routine every time clock come to 12:00
Is there any system api for this?
How i do this?
actually i have a status bar item in my app that show current day in month in any selected calendar like gregorian and islamic, and i want to this value will be sync with system time
If your routine is the method - routine:(NSTimer *)timer of object:
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; // Current time
NSTimeInterval then = ((int)now + 86400) % 86400; // Next 12am
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:then];
NSTimer *timer = [[NSTimer alloc] initWithFireDate:date interval:86400 target:object #selector(routine:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
I'm creating an NSTimer:
NSTimer *saveProgressSizeTimer = [[NSTimer alloc]
initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:2.0f]
interval:1.0f
target:self
selector:#selector(myMethod:)
userInfo:myUserInfo
repeats:YES];
However, the timer doesn't get fired. The method doesn't get invoked.
If I print my date I get the following:
2012-10-12 15:19:02.786 MyApp[1768:303] fire date: 2012-10-12 13:21:02 +0000
Shouldn't it be "2012-10-12 15:21:02" ? Somehow the hours are wrong. But why? If I change the Time Zone from UTC/GMT +1 hour (I'm sitting in Germany) to another, the date is still 2012-10-12 13:19:02 plus two seconds.
What am I doing wrong?
Thanks!
A time created with initWithFireDate must be added to a run loop, e.g.
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
Use scheduledTimerWithTimeInterval to create a timer that is automatically scheduled on the current run loop.
PS: The description method of NSDate uses always GMT, that probably explains your output.
addTimerIf you create your timer like this:
NSTimer *saveProgressSizeTimer = [[NSTimer alloc]
initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:2.0f]
interval:1.0f
target:self
selector:#selector(myMethod:)
userInfo:myUserInfo
repeats:YES];
You must add the timer in the RunLoop like this:
[[NSRunLoop currentRunLoop] addTimer:saveProgressSizeTimer forMode:NSDefaultRunLoopMode];
Here is my code
[NSTimer scheduledTimerWithTimeInterval:0
target:self
selector:#selector(t:)
userInfo:endtime
repeats:YES ];
-(void)t:(NSTimer *)timer
{
if ([timer.userInfo timeIntervalSinceNow] < 0) {
[timer invalidate];
}
Is it possible to set the time between calls to t method, because the default is too fast for me ?
Is it possible to set the time between calls to t method, because the
default is too fast for me?
Right now you're passing 0 for the interval. Use a larger value for a longer interval:
NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:60
target:self
selector:#selector(t:)
userInfo:endtime
repeats:YES ];
This schedules the timer to fire every 60 seconds.
The first parameter is the time interval (in seconds) inbetween the calls (see NSTimer doc), where you did set 0. So you can for example set 0.5 for "once ever half second" or 1 / 30.0 for "30 times a second". Note that NSTimer calls are not absolutely exact and you may have to calculate the exact time since last call if you need accuracy (e.g. animations).