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
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:
How to change the NSTimeInterval of an NSTimer after X seconds?
(2 answers)
Closed 7 years ago.
What I am trying to do is increase the speed of an NSTimer in swift to increase the speed of a function gradually without making a million different NSTimers. If there is a way to do that, how do you? And if this is not the correct way of doing that, what would the best way be? Thank you.
You can destroy the timer and re-create it with a different interval when you want to increase its speed.
You can also have a single timer that runs at the fastest possible interval, and then ignore the callback unless time % some_number == 0 then gradually make some_number smaller and smaller.
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".
I am making a game and watch style game (remember Donkey Kong?) where all the enemies move at a set interval.
Eg. the barrels in donkey kong might move 1 step at precisely every 1 second. Accuracy is vital because the player needs to anticipate the movement and plan their jump.
I am using an NSTimer to run a function that essentially handles moving all the enemies forward one step. This was working great but then I noticed that every now and the enemies would briefly freeze, which wrecks the game. Reading the NSTimer documentation, it seems this is just the way it is when working with NSTimers.
What I tried:
I was originally using scheduledTimerWithTimeInterval but read another thread which suggested using timerWithTimeInterval along with
[[NSRunLoop currentRunLoop] addTimer:autoMoveTimer forMode:NSRunLoopCommonModes];
But I still noticed the freezing.
Instead of running the timer every second, I tried making it run much more often and then inside the function check the elapsed time with
NSTimeInterval elapsedTimeInterval;
elapsedTimeInterval = [gameTickerLastRan timeIntervalSinceNow];
if(elapsedTimeInterval<-gameSpeed){
NSLog(#"%f since ticker last ran",elapsedTimeInterval);
gameTickerLastRan=[NSDate date];
//do stuff in function
}
but still I noticed the freezing, even though the elapsed times being output seemed pretty accurate to me.
-1.006408 since ticker last ran
-1.006985 since ticker last ran
-1.007313 since ticker last ran
-1.007193 since ticker last ran
-1.006768 since ticker last ran
-1.007468 since ticker last ran
-1.007429 since ticker last ran
-1.006759 since ticker last ran
-1.007435 since ticker last ran
At the end of that function, after all the enemies had been moved on a step, I tried forcing the graphics to update with
[self performSelector:#selector(sweetNothings) withObject:nil afterDelay:0.0];
But this didn't help.
I briefly tried creating a dedicated thread for the timer but what I tried didn't work and I felt too out of my depth to experiment much with that.
The storyboard contains about 100 UIImageViews which are laid out like a frame by frame animation. I then turn these on and off using their hidden property to create the animation.
Can anyone suggest a rock solid way for me to run this function at a precise interval and get around the graphic freezing?
EDIT: I tried a CADisplayLink but it seems exactly the same - ie it is still freezing up for a second roughly every 10 seconds. This is what I have
displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(gameTicker:)];
[displayLink setFrameInterval:1];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
and then in game ticker I have
CFTimeInterval elapsedTime = displayLink.timestamp - lastDrawTime;
NSLog(#"elapsed %f", elapsedTime);
if(elapsedTime>=gameSpeed){
//do stuff
lastDrawTime = displayLink.timestamp;
}
EDIT 2: Well I'm embarrassed to say that I just realised that it wasn't lag at all. I was removing elements while looping through an array forward, which was causing the illusion of lag. Thank you for pointing me to CADisplayLink anyway - looks very useful. Should I delete my question?
Have a look at CADisplayLink (this is what Cocos2d and other game frameworks use).