I'm trying to implement a countdown feature for my program. It's a second-timer, so I use a NSTimer object with a time interval of 1.0 second to update the UI. But in order not to accumulate error (every 1.0-second interval will incur a little bit of lag), the program caculates the absolute difference between current time and beginning time for the remaining time displayed in the UI.
The problem is, after the NSTimer object runs for a significant time (say half an hour), it's no longer "synced" with the absolute time due to accumulated error: the UI update happens between two "absolute" seconds. For example, if the countdown starts at 00:00:00.000, at first UI updates at 00:00:01.000, 00:00:02.000 ... but after a while it becomes 00:30:03.567 or something like that.
Any idea how I can deal with this? Are there any other better ways to implement this? Thanks!
One high level idea is to detect when the timer is getting too far out of sync based on your absolute time calculation. When it gets past a specific threshold, say 0.01 seconds or whatever you desire, cancel the current timer and start a new one after an appropriate delay that gets it back "in sync".
Related
In a Gtk::DrawingArea I have a pixbuf showing the layout of my house. I draw the measured room temperatures on it. I also would like to draw the state of my shutters on it with some lines. When and only when a shutter changes its state, I would love to make these lines blink with a time offset of 1 second. I assume, I would have to make use of a timeout triggered every second to redraw the lines for the shutters. I am already making use of a timeout every 2 minutes to fetch new data from the internet to be shown on my screen. I could set up the timeout to get called every second and then I would have to remember, when my last 2-minute fetch was accomplished, to trigger the next one on time. Also, if my shutters are not changing state like in 99.9 percent of their lifetime, I do not need blinking. It feels over engineered to me to call a method every second just to make a line blink. Is there a smarter way to do this?
I could post a lot of code here, but I think that would not help anybody understand my question. I am helpful for any hint.
In my app, a user can "speed-read" text by having words flashed on the screen at a speed that they set. I have coded up this functionality in my UIViewController using a repeating NSTimer and updating the UILabel by displaying the next word index, but it's not going as fast as it should be.
For example, I tested it with 100 words at 1000 words per minute. Instead of taking 6 seconds like it should be, it takes 6.542045 to finish flashing all of the words. This is a big problem since I'm supposed to spit back to user user how long it took for them to read the text.
How do I find out what part of the code is taking so long? Is it the updating of the UILabel that's eating up 0.54~~ of the time?
EDIT
My sample project can be viewed here: https://github.com/cnowak7/RSVPTesting
The flashText method that I have should be firing only 100 times. Well, 101 if we count the time when the method realizes there are no more words and terminates the NSTimer. In the console, at the end of reading, I can see that the method is being fired 111 times. I think I might be doing this the wrong way.
Your specific question seems to be: How do I find out what part of the code is taking so long? Is it the updating of the UILabel that's eating up 0.54~~ of the time?
Inside Instruments, provided with Xcode, is a Time Profiler tool.
https://developer.apple.com/library/ios/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Instrument-TimeProfiler.html
You can run your code and watch this tool to see exactly how much time is being spent executing every part of your routines. It will break down exactly which method is taking the most time, by percentage of overall time and concrete time spans, giving you a precise understanding of where you should focus your efforts in shaving off those precious partial seconds through refactoring/optimizations.
I'm an Objective-C guy, so rather than try to muddle my way through a Swift example, I'll let this guy do the talking.
https://www.raywenderlich.com/97886/instruments-tutorial-with-swift-getting-started
Whenever you want to know about time consumption in iOS you should always go for Instruments and select time profiler as shown in the image.
Time profiler will help you get to the code which is taking too much time.
This question already has answers here:
Format realtime stopwatch timer to the hundredth using Swift
(2 answers)
Closed 7 years ago.
I've got a 9 figure number that needs to be incremented by 500 each second, but i decided to increment the number each milliseconds and update the label that displays the number. I'm using a NSTimer but as i've read everywhere around they're not accurate nor meant to be. I've tried using CFAbsoluteTimeGetCurrent but couldn't get it to work. Simply using NSTimer yields and inaccurate value. The incrementation doesn't stop each time the user opens the app it simply adds up the value and starts incrementing again.
Any Ideas?
Update:
Even though most answers point in the right direction, i solved my issue a little bit different. Thanks to all who answered and Martin.
I used a CADisplayLink instead of a NSTimer and got pretty accurate and constant results. Now notice i say pretty because the results are not totally accurate, but since in my case i'm incrementing a 9 figure number they're not noticeable, and my numbers are corrected as soon as the view appears again.
You can get Accuracy
timer = [NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:#selector(countup)userInfo:nil repeats:YES];
Use a timer only as a trigger to update the screen, do not rely on the exact time between each fire.
Keep an NSDate which represents the start time and use the current date when the timer fires to calculate the difference and update the label.
Consider using CADisplayLink to update your interface — it gives you very accurate numbers of the time passed since the previous frame was drawn, so you can always keep your UILabel up to date, regardless of how high or low your framerate is.
The Time won't be very accurate - but it doesn't need to be, if you get the accurate current time each time you go into the loop and add 500 x (whole number of seconds), you will get a display that increases by 500 each second (plus / minus 50-100 milliseconds)
The advantage of this approach is that you won't get an ever-increasing discrepancy in the timing, only ever 50-100 milliseconds.
If you want the timer to stop when the user switches out of the app, then you need to disable the timer when the app becomes inactive - have a look at this tutorial on the Ray Wenderlich site http://www.raywenderlich.com/92428/background-modes-ios-swift-tutorial
I develop a method where each 3 seconds I show a image moving. I make with dispatch_after, but in each execution of the app, the distance or the time when the image is shown it's diferent. Is more efficient use an NSTimer with a Schedule??
Yes, NSTimer is high level API and easy to implement and control like if you want to pause or stop that animation you can do it. But GCD is better in performance as I know.
I think for a repeating time period NSTimer is the more obvious choice. Apart from anything else you need to make sure that one and exactly one dispatch_after is called for each time you get called.
With a dispatch_after chain there may be a risk that there will be a slight drift in timing as delays add up where with the NSTimer if one event is slightly late there should be a fractionally shorter delay to the next one so that it doesn't suffer drift over time.
It seems like the highest timer rate on iOS is 60 times per second using CADisplayLink, which is 0.01666 second each time. Can two timers be set up at the same time, so that an image can be updated more frequently for its location?
Or, can one timer event handler fire off another timer event 0.00833 second later, so that there is another update in between the 1/60 intervals, to achieve 120 fps?
Why would you want to achieve 120 fps on a screen that updates 60 times a second?
That would just waste CPU and power. Don't do it.
However, having a timer that fires more often is definitely possible.
Drawing in each of these callbacks is, however, is not possible. (at least using -drawRect:, don't know about OpenGL).
You can't do this for a number of reasons. First, there's a hard cap at 60fps due to hardware limitations. Second, NSTimer is not nearly accurate enough for this sort of thing. From the Timer Programming Topics - Timer documentation (bold added for emphasis):
Timing Accuracy
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 while the run loop is in
a mode that is not monitoring the timer or during a long callout, 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.