Set time between NSTimer selector calls - objective-c

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).

Related

Objective-C, scheduledTimerWithTimeInterval Progressive Increase

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;

Can we update the variables that are manipulated by NSTimer?

I am using NSTimer that updates 2 different values secondsLeft and totalSecondsLeft. I don't have to change secondsLeft but I have to add more seconds to totalSecondsLeft when an action is performed.
Whenever I assign a value to totalSecondsLeft the timer still updating and printing the previous value. I saw different solutions and tried invalidating the timer and start it again after updating the totalSecondsLeft value but not working.
So I ended up creating 2 different instances of the timer with same variables but printing different values i.e, secondsLeft is same in both cases but totalSecondsLeft is different in both cases.
I tried many solutions and added timer instance to GCD main_queue using functions and invalidating the timer from the same queue still not getting working solution.
Here is my code:
[self settime];
-(void)settime
{
dispatch_async(dispatch_get_main_queue(), ^
{
timer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(Countdown) userInfo:nil repeats:YES];
});
}
-(void) Countdown
{
secondsLeft=secondsLeft-1;
totalSecondsLeft=totalSecondsLeft-1;
NSLog(#"secondsLeft : %i and totalSecondsLeft : %i",secondsLeft,totalSecondsLeft);
}
-(void)otherMethod
{
dispatch_async(dispatch_get_main_queue(), ^
{
timer=nil;
[timer invalidate];
});
[self settime];
}
Help me to figure out. Thanks in advance

Getting Time Zone Time not updating in real time [duplicate]

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];
}

NSTimer repeating too fast

The Problem
I am building an app where I am getting real-time data and updating a MKMapView. I get a batch of data every 10 seconds and between data sets from the webs service I am removing older data points while also adding the new ones.
Instead of updating them all at once I want spread out the animation of the new points I get from the data service over that 10 seconds so I create the 'real-time' feel and avoid as many stops and starts as I can.
Everything seems to be working great except the that the NSTimer is always finishing early... way early. It should loop through the new data over 10 seconds but it will typically finish looping through the new data set 4 to 5 seconds earlier then it should.
I have read through a lot of the Apple documentation and StackOverflow questions (below are two good ones for those that may be looking) :)
https://stackoverflow.com/a/18584973
https://developer.apple.com/library/ios/technotes/tn2169/_index.html#//apple_ref/doc/uid/DTS40013172-CH1-TNTAG8000
But it seems like most of the recommendations are made for gaming apps using CADisplayLink (but I am not building a gaming app) or that if you need to use a high performance timer that it should not be used continuously.
My timer does not need to be exact but if I could even get it within .5 seconds that would be great without having to add the overhead of some of the other options I have seen.
As always any thoughts / code / or directions you could point me would be greatly appreciated.
The Code
Once I collect the new data into arrays I create the time interval and start the timer with the code below
addCount = -1;
timerDelay = 10.0/[timerAdditions count];
delayTimer =[NSTimer scheduledTimerWithTimeInterval:timerDelay target:self selector:#selector(delayMethod) userInfo:nil repeats:YES];
That then fires this method that animates through adding and removing the my map annotations.
-(void) delayMethod {
addCount = addCount +1;
if (addCount >= [timerAdditions count]) {
[timerRemovals removeAllObjects];
[timerAdditions removeAllObjects];
addCount = -1;
[delayTimer invalidate];
delayTimer = nil;
} else {
[myMap addAnnotation:[timerAdditions objectAtIndex:addCount]];
[myMap removeAnnotation:[timerRemovals objectAtIndex:addCount]animated:YES];
}
}
UPDATE
I tried updating my timer through GCD. And what is odd is that the timing loop works every other dataset. Still do not have it working every tie but for some reason it seems to be tied to resetting the dispatch time or the timer interval.
-(void) delayMethod {
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * timerDelay); // How long
dispatch_after(delay, dispatch_get_main_queue(), ^(void){
addCount = addCount +1;
if (addCount >= [timerAdditions count]) {
[timerRemovals removeAllObjects];
[timerAdditions removeAllObjects];
addCount = -1;
//[delayTimer invalidate];
//delayTimer = nil;
} else {
NSLog(#"Delay fired count %i -- additoins %lu",addCount,(unsigned long)[timerAdditions count]);
[myMap addAnnotation:[timerAdditions objectAtIndex:addCount]];
[myMap removeAnnotation:[timerRemovals objectAtIndex:addCount]animated:YES];
[self delayMethod];
}
});
}
I am using timer as like this to do stuff with timer instance for more accurate result.
- (void)createTimer {
// start timer
if(gameTimer == nil)
gameTimer = [NSTimer timerWithTimeInterval:1.00 target:self selector:#selector(timerFired:) userInfo:nil repeats:YES] ;
[[NSRunLoop currentRunLoop] addTimer:gameTimer forMode:NSDefaultRunLoopMode];
timeCount = 725; // instance variable or you can set it as your need
}
- (void)timerFired:(NSTimer *)timer {
// update label
if(timeCount == 0){
[self timerExpired];
} else {
timeCount--;
if(timeCount == 0) {
// display correct dialog with button
[timer invalidate];
[self timerExpired];
}
}
//do your stuff here for particular time.
}
- (void) timerExpired {
// display an alert or something when the timer expires.
NSLog(#"Your time is over");
[gameTimer invalidate];
gameTimer = nil;
//do your stuff for completion of time.
}
in this take time interval you want. and also Increment decrement stuff as you require. And do stuff with timer fired and completed. In your situation if you don not want to expire timer than its ok. never invalidate timer instance and use only timer fired event to do stuff.
I went down a slightly different path thanks to another SO question I have referenced below. Basically by combining the two timers into one, setting that one timer to the fastest time interval I would need and managing the methods I need to at the changing intervals within the method called by the timer I have solved the problem I was seeing.
https://stackoverflow.com/a/25087473/2939977
timeAdder = (10.0/[timerAdditions count]);
timeCountAnimate = timeAdder;
[NSTimer scheduledTimerWithTimeInterval:0.11 target:self selector:#selector(timerFired) userInfo:nil repeats:YES];
- (void)timerFired {
timeCount += 0.111;
if (timeCount > 10.0) {
// call a method to start a new fetch
timeCount = 0.0;
timeCountAnimate =0.0;
[self timerTest];
}
if (timeCount > timeCountAnimate) {
timeCountAnimate += timeAdder;
[self delayMethod];
}

NSTimer - Why does scheduledTimerWithTimeInterval work, yet initWithFireDate doesn't?

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