I have a problem with NSTimer. I start and repeat it every 100ms and I have a counter to check if i runed 10s. The problem is it stoped in near 1 minute, not in 10s.
Here is my code
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(checkTimer) userInfo:nil repeats:YES];
-(void)checkTimer
{
timerCount += 1;
if(timerCount == 1)
{
NSLog(#"start");
}
if(timerCount == 103)
{
NSLog(#"i got it");
}
}
here is the log:
2012-11-19 08:57:42.063 Karagram[11708:540b] start
[Switching to process 8707 thread 0x2203]
2012-11-19 08:58:39.514 Karagram[11708:540b] i got it
I don't understand why it wrong. Somebody can tell me why?
Thanks.
NSTimers aren't guaranteed to be accurate to within more than 100 ms or so. The NSTimer documentation says:
A timer is not a real-time mechanism; it fires only when one of the
run loop modes to which the timer has been added is running and able
to check if the timer’s firing time has passed. Because of the various
input sources a typical run loop manages, the effective resolution of
the time interval for a timer is limited to on the order of 50-100
milliseconds. If a timer’s firing time occurs during a long callout or
while the run loop is in a mode that is not monitoring the timer, the
timer does not fire until the next time the run loop checks the timer.
Therefore, the actual time at which the timer fires potentially can be
a significant period of time after the scheduled firing time.
By having it fire every 100ms you're compounding the error, because if it's off 50 ms every 100ms, by the time 10s has passed it could be quite far from what you expect.
If you're wanting to take some action after 10s, why not just set the timer to fire after 10s?
NSLog( #"start" );
timer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:#selector(checkTimer) userInfo:nil repeats:YES];
-(void)checkTimer
{
NSLog(#"i got it");
}
Also, are you doing your streaming on the main thread? NSTimers work on the main runloop, so if you're blocking the main thread, timers aren't going to fire until it's unblocked.
Related
I'm trying to stream data to a server at regular intervals and do so in a way that is fast and does not block the UI. The UI is also pretty busy trying to display the data. Currently my implementation uses NSTimer that fires every 50ms, picks a network packet out of a circular array and sends it over:
//this is the timer
networkWriteTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(sendActivity:) userInfo:nil repeats:YES];
-(void)sendActivityInBackground:(id)sender
{
[[AppConfig getInstance].activeRemoteRoom.connection sendNetworkPacket:[circularArray objectAtIndex:arrayIndex%arrayCapacity]];
}
-(void)sendActivity:(NSTimer*)timer
{
// Send it out
[self performSelectorInBackground:#selector(sendActivityInBackground:) withObject:nil];
}
I'm not satisfied with the performance of this method. Time profiling has revealed that there's overhead associated with performing background selectors, and the performance can get quite choppy.
I'm thinking of additional ways to improve performance:
Improve the performance of the current timer based code
Try grand central dispatch
Implement NSOperationsQueue with a single operation.
Use a dedicated thread that wakes up, checks for update and sends it over if needed
Ideally, I would send data at even faster intervals (10ms or even for each activity update). This poses the question: What is the fastest way to implement a sequence of background send requests, where order matters? I want to make sure that one packet gets send before the next one is being sent.
Try a recurring dispatch timer (that is part of gcd):
self.synchronizerQueue = dispatch_queue_create("synchronizer queue", DISPATCH_QUEUE_SERIAL);
self.synchronizeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.synchronizerQueue);
dispatch_source_set_timer(self.synchronizeTimer, DISPATCH_TIME_NOW, NSEC_PER_MSEC * 10, NSEC_PER_MSEC * 1);
dispatch_source_set_event_handler(self.synchronizeTimer, ^
{
// do your processing here
});
dispatch_resume(self.synchronizeTimer);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Xcode: Why is my timer count 2 seconds on every tick?
In my app I have a timer that should go from 12:00 to 0:00, but it counts 2 seconds on every tick like this:
11.58
11.56
11.54
11.52 and so on..
this is the code in the start button code:
tid.text=[NSString stringWithFormat:#"%d:%.2d",minuter,sekunder];
timer= [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(tidklick)
userInfo:nil
repeats:YES];
This is the method tidklick:
-(void) tidklick
{
tiden -= 1;
sekunder = tiden % 60;
minuter= (tiden - sekunder) / 60;
tid.text=[NSString stringWithFormat:#"%d:%.2d",minuter,sekunder];
}
This is the code in the beginning..
int tiden=720;
int sekunder;
int minuter;
and also when I hit a certain button, this should happen: i++;
but it seems like i gets added by 2 every time I hit the button....
What is wrong? :S Seems like something with Xcode and not my code?
EDIT: Now I noticed that when I hit the button that should stop the timer in the end(timer invalidate), it counts as normal... It counts one second at a time that is!
Thanks in advance!
For the second part of the question, when you hit your button: Have you made sure that your selector for the button isn't being called twice -- for instance when the button is pressed down and then again when it is lifted up.
When you say you 'hit the button', what is your button hitting code? There are several events that take place on a button "hit" (most notably button down and up events) which if you are not handling properly could increment i multiple times in a single 'hit'.
This could also be the reason the timer is doing down by two instead of one -- when you 'hit' the start button you are launching two timers instead of one, causing one second per timer to be decremented per second.
For better time counting try to use NSDate methods:
[NSDate date] for start value and [NSDate timeIntervalSinceDate:startTime] to get time shift from the start.
Timer firing interval is approximately equals to 1 second.
I am working on an application that needs a method to be called at a certain time (15 minutes past the hour to be exact). Is there a way to make this happen without consuming a ton of CPU and battery life? I've tried searching and just can't find an answer anywhere.
They made this really easy. Alloc an NSTimer and initialize it with the fire date, using:
-(id)initWithFireDate:(NSDate *)date
interval:(NSTimeInterval)seconds
target:(id)target
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats
then add it to the run loop using:
-(void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode
on the run loop, e.g. [NSRunLoop currentRunLoop]. Don't know if this will wake the device, or prevent it from sleeping.
edit some example code
// start in 5 minutes
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:300];
// fire every minute from then on
NSTimer *t = [[NSTimer alloc]
initWithFireDate:date
interval:60
target:self
selector:#selector(stuff:) // -(void)stuff:(NSTimer*)theTimer
userInfo:nil
repeats:YES
];
// make it work
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
and
-(void)stuff:(NSTimer*)theTimer
{
if ( done ) [theTimer invalidate];
}
If you need this to happen while your application is not running, have a look a UILocalNotification in iOS 4.0. It's unclear whether your application is running at the time that you need this notification or not, but in either case this class should get you pointed in the right direction.
http://developer.apple.com/iphone/library/documentation/iPhone/Reference/UILocalNotification_Class/Reference/Reference.html#//apple_ref/occ/cl/UILocalNotification
Okay, I have searched online and even looked in a couple of books for the answer because I can't understand the apple documentation for the NSTimer. I am trying to implement 2 timers on the same view that each have 3 buttons (START - STOP - RESET).
The first timer counts down from 2 minutes and then beeps.
The second timer counts up from 00:00 indefinitely.
I am assuming that all of the code will be written in the methods behind the 3 different buttons but I am completely lost trying to read the apple documentation. Any help would be greatly appreciated.
Basically what you want is an event that fires every 1 second, or possibly at 1/10th second intervals, and you'll update your UI when the timer ticks.
The following will create a timer, and add it to your run loop. Save the timer somewhere so you can kill it when needed.
- (NSTimer*)createTimer {
// create timer on run loop
return [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerTicked:) userInfo:nil repeats:YES];
}
Now write a handler for the timer tick:
- (void)timerTicked:(NSTimer*)timer {
// decrement timer 1 … this is your UI, tick down and redraw
[myStopwatch tickDown];
[myStopwatch.view setNeedsDisplay];
// increment timer 2 … bump time and redraw in UI
…
}
If the user hits a button, you can reset the counts, or start or stop the ticking. To end a timer, send an invalidate message:
- (void)actionStop:(id)sender {
// stop the timer
[myTimer invalidate];
}
Hope this helps you out.
I would follow Jonathan's approach except you should use an NSDate as your reference for updating the UI. Meaning instead of updating the tick based on the NSTimer, when the NSTimer fires, you take the difference between NSDate for now and your reference date.
The reason for this is that the NSTimer has a resolution of 50-100 ms which means your timer can become pretty inaccurate after a few minutes if there's a lot going on to slow down the device. Using NSDate as a reference point will ensure that the only lag between the actual time and the time displayed is in the calculation of that difference and the rendering of the display.
how to add timer to loop. i am making a urlConnection so i want that the loop execute for a time and if there is no connection it should exit.
Does it work.....
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1f]];
Thanks in advance.
NSURLConnection has a method - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode. Is this what you're looking for?
Sounds like you want #selector(timerWithTimeInterval:target:selector:userInfo:repeats:).
"Returns a new NSTimer that, when added to a run loop, will fire after a specified number of seconds." See http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/Reference/NSTimer.html
Set repeats:YES and invalidate the timer after your timeout value is reached.
If you are trying to make your url connection attempt time out after a certain interval, you would be far better off looking at the timeout value on NSURLRequest. Synchronous connections should be avoided wherever possible.