views:

79

answers:

3

I have a requirement in my app which requires me to display some message to the user if there is no activity happening for about 3 hours on the app/ipad. I considered the solution of having an NSTimer that would start at launch. If the user performs any action, I invalidate the timer and start a new one. However, there is video playback on the app and for all I know, the user may be watching the video for about 3 hours and performs no other action during that time and would still get the message.

So, an alternative is to invalidate and start the timer every time I detect the ipad/iphone has moved. In other words, use the accelerometer and in the call back to detect acceleration, I can invalidate and create the timer again. But my worry with this approach is that even for smallest of movements, the timer would have to be invalidated and recreated. Will this approach in any way impact performance?

Thanks and Regards, hetal

A: 

Apple has a feature in multitasking that they call "Task finishing" use by - (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void(^)(void))handler Found here and more stuff here

Matt S.
That wouldn't serve the purpose. I need to detect 3 hours of absolutely no activity or movement. So, even the slightest movement needs to invalidate old timer and start another timer. Any idea on the performance impact?
Hetal Vora
See my new edit
Matt S.
A: 

Creating a timer is not that expensive, but it's still a little expensive.

The good news is that you can arbitrarily change the fire date:

[timer setFireDate:[NSDate dateWithTimeIntervalSinceNow:3*60*60]];

Alternatively, for very slightly less overhead:

CFRunLoopTimerSetNextFireDate((CFRunLoopTimerRef)timer, CFAbsoluteTimeGetCurrent()+3*60*60);

(I think the CFAbsoluteTimeGetCurrent() overhead is more than the object-creation overhead, but meh.)

A slightly better solution might be to leave the timer alone most of the time; simply update the "last activity" timestamp. When the timer fires, look at the "last activity" timestamp. If it's more than 3 hours ago, thenshow the notification. If it's less than 3 hours ago, then set the next fire date appropriately; this means the timer fires (on average) at most every 1.5 hours, which is probably not as costly as repeatedly changing the fire-date.

See mach_absolute_time() for a relatively low-overhead timebase (pre-calculating what 3 hours is in mach_absolute_time units). It still takes about 3 microseconds, which is practically forever (1000 clocks cycles!).

If you're really worried about overhead, simply set an "activity" flag every time something happens, and use (e.g.) a 1 hour timer. When the timer fires, do something like if (activity) {counter = 0; activity = 0; } else { counter ++; if (counter == 3) { ... } }. It's debatable whether a couple of microseconds here and there are more costly than a timer firing every hour, but they're both pretty negligible.

The far bigger problem is that the accelerometer eats power and CPU time (and delivering updates takes CPU time). Setting updateInterval = 10 or so will reduce the overhead, and it's capped to a sensible value (around 1 s) by the OS.

tc.
A: 

Can't you just send a message to your NSTimer whenever a video starts, to invalidate the timer? Then when the movie ends, start the timer back up.

Calvin L