I'm working on an app that has an event timer that times an event (duh!) that can last a long time.
I've done other apps with timers over a fairly extended time period and never come across this problem before.
Basically, what's happening is that when the app launches, I set an NSDate value with [NSDate date]. Then, I have a scheduled NSTimer object that fires regularly and checks how much time has elapsed by comparing the current [NSDate date] value against the original one.
As far as I know, that's the correct way to do this sort of thing, but please correct me if I have a faulty assumption in the above paragraph.
Anyway, when testing on my new iPad over the last few weeks, I've variously (and randomly) caught a few times where it appears that my system time is jumping around a good bit. In one instance, the time seems to have jumped 64 seconds! This meant that my timer label displayed '00:03' and then immediately displayed '01:08' (add a second correctly and then 64 incorrectly)!!! At other times, it has resulted in a negative event duration.
It's an intermittent occurrence, so I'm basically asking whether this could be:
An iOS 5.1 bug
Something to do with the hardware specific to the new iPad (never had this issue on iPad 1st Gen, 2nd Gen, several iPhone/iPod Touch versions, etc...)
Bad Code (I'll admit this is possible, but it's not like the NSDate value ever becomes something other than an NSDate value, and I've checked every place in my project where this singleton value is set.
Has anyone had any similar experience? Can anyone help?
This is not a iOS device or OS version bug.
The NSDate API is not guaranteed to be consistent, or even monotonic, as you have found. It drifts (depending on temperature and such) and then gets corrected from either cellular or NTP sources, after which the date and time value can jump.
For a monotonic local timer, you can try the functions in mach_time.h . For a better absolute time reference, your app can try polling a network time source. Or you can tie your own time function to some combination of both.
Related
I have a timer app, it counts up for an indefinite amount of time (until the user stops the timer). It works much like the default iOS clock stopwatch.
I have read the articles about being a responsible background app. I don't have any UI changes happening and stop the timer when the app goes in the background and resume the timer upon returning to foreground. The app does send a local notification every 30 minutes or so to remind the user to take a break.
Problem: Without fail my app is terminated after a few hours (between 2-6 or so hours) and the current timer and info is lost.
Things I've tried:
-As aforementioned I changed my app to follow the guidelines of being a responsible background app (before I had the timer UI counting up and also the timer running, even while in background). I thought this would solve the problem since my app isn't using up much memory or doing any intensive tasks.
-I also have tried saving out the data of the current timer (to NSUserDefaults) in ApplicationWillTerminate and then restore it on DidFinishLaunchingWithOptions. It doesn't seem to work. It's almost like my app is force quit or something because if ApplicationWillTerminate was being called then it would save the data and restore it upon the app launching again. Mystery.
-Currently I'm saving an NSDate of the start time of the NSTimer on ApplicationDidEnterBackground, invalidating the timer, and starting the timer and restoring the start time upon ApplicationWillEnterForeground. Still no luck.
The thing is this is affecting a very small percentage of my users--so it's not like it's a problem for everyone, which makes it more confusing. I still want to fix it of course because it's a pretty lame bug--and I've encountered it myself (on an iPhone 5), so it's not necessarily an old iPhone low memory somethingorother problem.
This has really boggled me, I've done my research and also scoured fairly well the stack overflow questions and don't seem to find much of anything to help me.
Any help would be appreciated, feel free to ask more questions or tell me to clarify.
applicationWillTerminate is basically never called. It will not be called when your app is in the background and it gets removed from memory. You should expect your app to be removed from memory if it hasn't been used for a while. How long "a while" is depends on what else the device is doing at the time... Best to use applicationDidEnterBackground: or applicationWillResignActive:.
When your app goes into the background, record your timer's elapsed time (eg: in NSUserDefaults or however you prefer). Also record the current time. When the app comes back into the foreground, look at the two values you recorded and update the elapsed time accordingly, ie:
elapsedTime = savedElapsedTime + (currentTime - timeWentIntoBackground)
There's really no reason your app needs to remain active in the background burning the user's battery just to keep track of seconds ticking by.
Also, don't rely on applicationWillTerminate. Use applicationWillEnterBackground.
In a cocos2D powered iphone app, I use the CCRepeatForever action to make the background pass by. It works fine when I debug the app (build and run via XCode). Even if I quit the app and resume it, no problem.
However when I bundle the app into an .ipa for beta testing I get a weird problem :
At launch the background passes by nicely. But if I quit the app and resume the game later, the app takes me back where I left it, with everything working but the moving background. And after a time (roughly proportional to the time since I quitted the app) the background starts moving again as it should, without me doing anything particular.
Is this a know issue ?
Thanks
OH, I had a very similar problem a little while ago. I would pause the game, then on resume nothing would happen, then it would suddenly jump and I'd be swarmed with monsters.
I can't tell you precisely where to look, but here's what I was doing:
I had a timer that was not using the (ccTime)dt to calculate time, but was using an NSDate timestamp. The problem was that I had an event to be scheduled at a certain time based on the date, but was using the dt to figure out when to trigger the event.
As far as I could tell, pausing the game was halting the scheduled events, so the "dt" wasn't incrementing at all, but the system clock kept ticking, so what ended up happening is that I would pause for say 10 seconds, the system clock ticked up and triggered, but the "dt" was adding into a float timeElapsed, and until that caught up, nothing happened.
What you probably need to look for is something inside a scheduled event that is using an NSDate or a unix timestamp or the iPad/iPod system clock. When you halt the simulator, the system clock doesn't seem to run the same way it does on an actual iPad.
Sorry, I don't know EXACTLY how this stuff works, but I also went through an agonizing time with a similar problem and it was based on the system timer. Just make sure you're pausing everything with the CCDirector properly and make sure you're not using any system clock stuff for game timing
I am writing an iPhone game. When the user makes his first move a timer kicks of with an interval of 0.01 seconds. A UILabel displaying the time also gets updated every time.
I noticed when testing on an iPod touch 2nd gen and an iPhone 3GS that the iPod was slower (after 20 seconds the iPhone displayed 00:20,00 and the iPod displayed ~00:10,00). Is there a way to make this more reliable? If I'm correct, the NSTimer should run on its ow thread and should not be blocked by user interaction.
JNK
The NSTimer documentation states:
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.
So accuracy can be as bad as 0.1, not 0.01 seconds. Not to mention if your thread is blocked for some reason. So if your firing time is crucial you should be looking at other things. Read this SO post for kick-off. Apple had a metronome sample code (in which, obviously, timing is crucial) but I can't find it just now.
In any case, if you are implementing a timer with NSTimer, you should record your start time. Then, whenever you update your interface, simply take the difference of the current time and your start time (with NSDates).
make sure you're not basing a timer off of sleeps or delays. You should always update a timer based on things like number of clock ticks since program start or current time
sorry I'm not more familiar with your language
You can't rely on a timer to run exactly at the specified time intervals, so the time you are displaying should always be calculated by taking time interval differences. And I doubt that a timer on the iPhone can run every 1 ms, in Quartz it is possible to get a timer call every 16 ms or so, making 60 fps - so scheduling it at 1ms probably means "run as soon as possible", which might be quite different on different hardware.
i'm looking at displaying the current time in HH:mm format, and ive been checking around for the best way to do this.
Most examples have a Timer being executed every second, updating a textlabel for example.
Now, i'm imagining that this might drain a bit of battery if it's to run every second, which seems like overkill if all i'm displaying is hours and minutes. On the other hand, i don't want the minute-switch to happen 30 seconds later than the actual minute switch...
Is there some way to get a call when the phone clock changes minute or something like that?
Don't worry about the battery. NSTimer exists for this purpose. Use it!
Here's an idea:
Calculate the time interval between now and the next minute start
schedule a one off NSTimer to fire after that time interval
update the display when it fires
Go back to step 1.
I have developed a test for iPod/iPhone (with MonoTouch if that is relevant) that measures reaction time. But I need to take into consideration the time between touching the screen and actual triggering of the button event. Is there any documentation of that?
It's already very hard to almost impossible to get predictable interrupt latency on real time operating systems.
But on the iPhone? Imho impossible. A capacitive touchscreen is not optimal to get results that are exactly the same for each body and location. And if mail.app decides to poll for emails just at the moment you'll touch the screen there will be a bigger delay.
But to make one thing clear, we are speaking about some micro seconds or even less than that.
If you want accurate results you shouldn't use an iPhone. But I guess your app will be some kind of game, so nobody cares if your result is 0.01 seconds off. But I wouldn't show results as 0.381829191 seconds, that fakes accuracy you'll never get on any smartphone.
What is the lowest reaction time you got in your app?
The time between an actual touch and the system registering it will be negligable.
One key thing: if you are detecting the press using touch events like touchUpInside, consider using the touchesDownInside event because touchesUpInside, will not fire until the user's finger leaves the screen.