A few iOS gotchas: NSDate copy, sleep and multitask
Posted in :
I was working on a new app and this app has something to do with timing. Basically I need to record the time between a button being displayed and the time a user touches the button (note they are in two different functions).
NSDate and memory leak
To accomplish this, I am using NSDate class, I declared NSDate * start in the class,
and then in one function, I was doing
start = [NSDate date];
and in the second function, I was doing
NSDate *methodFinish = [NSDate date];
NSTimeInterval intervalTime = [methodFinish timeIntervalSinceDate:start];
But the code above crashes immediately. After some research I believe this has something to do with memory, if we copy (retain) the NSDate as suggested by this thread in iphonedevsdk.com. It worked.
NSDate* now = [NSDate date]; // unretained
start = [now copy]; // retained
Sleep is another problem I have, actually I just need to pause a few seconds with the display not changing. Some suggested using C sleep function. This did not work for me as the display function was not working as I hoped. (Update May 30: When I think this more, I think the reason is sleep is a synchronous function, which blocks other threads including UI).
Eventually I did something similar to what suggested by Graham Lee. Quote Graham:
…Before going to sleep, register for a notification that calls the “after” code, and can be triggered by the UI (by an IBAction connected to whatever UI element). Now instead of calling sleep(), run the run loop for the period you want to go to sleep for, then after that has returned post the “after” notification. In the “after” code, remove the object as an observer for that notification. Now, whichever happens first – the time runs out or the user interrupts you – you get to run the “after” code…
I am also using NSRunLoop (as suggested by JimDusseau, same thread as above).
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
Multitasking change in iOS 4
Last but not least, incidentally when I was doing some persistence example on Beginning iPhone 3 development book, I found it no longer work as desired. Turns out applicationWillTerminate no longer gets called in iOS 4 (it is being called in iOS 3). The fix is call “applicationDidEnterBackground” instead. How to check whether a device has iOS 4 (multitasking) or older? Here is a tip from iPhoneDeveloperTips.com
if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)])
// Multi-tasking code for supported devices
// Devices without multi-tasking support
BTW, I found my apps myNestEgg and collegeFund both need this fix. Should have tested them more carefully in iOS 4 🙂