How to keep NSTimer alive? - iphone

I have 2 viewControllers in my app, from first view when i navigate to next one there is a button named startTimer with a timer action as selector method on Click of startTimer the timer starts up in HH:mm:ss format, i am not invalidating timer,but When i go back to 1st viewController and again if i come to again 2nd viewController and if i press startTimer button the timer again starts from 0, but i want it to be retained the previous value,how can i achieve this? i know that since i'm loading again the viewController the nib will be loaded freshly to memory but how can i retain the timer label and timer value?
Any help is appreciated in advance.thank you.

You've broken MVC (Model-View-Controller) by putting your data into your view controller. Moreover, you're asking a mechanism with no solid promises about time (NSTimer) to keep track of time for you. NSTimer does not fire exactly at the interval you request. It can fire at any arbitrary point after that interval. Using NSTimer as a stopwatch will almost always lose time (sometimes quite a lot of time, particularly if there's a scrollview around). (That last bit is overstated. A repeating timer schedules itself correctly so won't usually lose time. You'll just lose time if a repeat is completely skipped, which can happen during long scrolls or other things that can keep timers for firing for a full second.)
Create a new model object to hold the stopwatch information. Let's call it Stopwatch. Assuming you need it to be startable and stoppable, it needs an NSTimeInterval accumulatedTime property and an NSDate lastStarted property (you could also make lastStarted an NSTimeInterval if you like). So to start the stopwatch, you set lastStarted to "now." To stop the stopwatch, you clear lastStarted and move the current accumulated time to accumulatedTime. To find out the current time, you add accumulatedTime to now - lastStarted.
OK, now that you have that, what can you do with it? You can pass it to your view controllers and they can ask "what's the current stopwatch value?" They can start and stop it as they like.
Now your view controller would like to update its display every second, so you have a timer that does that. Every second it asks the stopwatch, "what's the current time" and it displays it. But it does not set the time. It just asks.
BTW, you can also use KVO on Stopwatch, but it's a little trickier, since Stopwatch needs to run its own timer to send out the change notifications. I generally find this more trouble than its worth.

Don't do like that, this way every time you load the view containing the NSTimer, a new NSTimer object is created and the old one is still in the memory since you're not invalidating it.
The best way is that you must put NSTimer in the Application Delegate and then start it only when you first time load that View Controller.
For achieving this, you must put a flag to check that the View is loaded first time or not.

If the NSTimer is one of your instance variable, I guess you could do a check to see if it is allocated or not.
//NSTimer *timer; declare this in your interface
if (timer==nil)
{
// allocate timer
}
//Do nothing if it is allocated all ready

What I would do is to mantain the second view controller as an ivar of your first view controller. This way, you can instantiate it just once and your NSTimer will remain in memory.
However, if you want to maintain your style, you should save the current time in any kind of preferences (look at [NSUserDefaults standardUserDefaults] or create your own singleton class). Then in view did load method from your second view controller, load that value and add it as an offset for your timer.
Hope to help!

Related

Fire method when a specific nsdate has passed

I want my App to call a method at an setter NSDate (It only needs to happen when the app is active, I'll handle passed events on launch in the app delegate).
I read about some ways to achieve such a behavior: On the one hand to work with performSelector:withObject:afterDelay: (But this doesn't look like a good way for me) or on the other hand to work with an NSTimer.
What is the best way regarding the app performance? One requirement is that you can cancel the event.
Using NSTimer is a simple solution. It has a property called fireDate that tells you when it's going to fire next. And it's a writeable property, so you can set that date to whatever you want.
Cancel the event by invalidating the timer object.

iOS: multiple NSTimer instances using the same view - do I need to use multithreading?

I'm working on a multiview app. One of the views is a table view. Each cell has a stopwatch. I'm planning to use NSTimer for the stopwatches. Do I need to implement multithreading for the timers to work properly even when the user switches the view and then comes back later?
I did my research but most of the tutorials cover one NSTimer in a single view. I want to make sure the user can do other things while the timers are running, like use the interface, navigation, etc. In another post Placing an NSTimer in a separate thread someone said you need a different runloop for the timer. Would I need one runloop for each timer in my case? Is it advisable? Any performance drawbacks?
Thanks a lot!
One run loop should be just fine. Your interface will still be responsive.
Keep in mind that timers are never guaranteed to be accurate. They are affected by how much other stuff is on the same loop. Its ok to use the timer to update the display but not to actually measure time. Set an NSDate when you start a stop watch then compare the current date with that start date each time your display timer updates the display.
Since you should only use the NSTimer to update the display, could you just use one generic display update timer that updates all running stopwatches, instead of having one for each stopwatch?

iPhone: Maintain Timer value between different views

I have built iPhone game application which has loads of views. The next view gets decided based on the user's current action. It working fine absolutely. I want to start a timer when my game gets started and want to keep incrementing till game finished. Nothing fency! The problem is I can put label on view and use NS Timer ticks to increment its value but how to synchronize that value when move to next view?
Could anyone please let me know if there is already framwork available that support this or any way to implement this.
Thanks.
The easiest solution would be to have the timer be a property in your app delegate, so you can access it from any view/view controller. That's what I'd do here. It doesn't seem to "belong" to individual views based on what you've described.

How to solve this performSelector:withObject:afterDelay: problem?

I have a view controller, which calls performSelector:withObject:afterDelay. However, if I remove that view controller right after calling this, my app crashes as soon as the system tries to perform the delayed selector on that (deleted) view controller.
Now how can I go about this? I need to get rid of the view controller to save memory, so there's no way to let it hang around.
Any way to cancel a delayed perform selector before it performs?
I suggest to use an NSTimer instead. You can simply invalidate the timer to make sure it will never be called after the UIViewController has gone away. A good moment to invalidate the timer is for example in viewWillDisappear:.
This does mean that the timer is owned by the view controller. But that is a good design anyway.
You can't perform a selector on a deleted object, you either need to have the object around, or do the work with some other smaller object that you can have hanging around.
To cancel there is a cancelPreviousPerformRequestsWithTarget:selector:object: or cancelPreviousPerformRequestsWithTarget: method.

Schedule timer with NSTimer makes the task run faster than expected

I schedule a timer with NSTimer's function in viewWillAppear as follows:
minutesTimer = nil;
minutesTimer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:#selector(updateScrollViewItems) userInfo:NULL repeats:YES];
With this function call, I expect it to call the selector updateScrollViewItems every minute, but it does not, it update items faster than expected (around some seconds).
What is the cause of this unexpected behavior?
It might not be the direct cause of the issue you're seeing, but I can already spot one major error.
The fact that this timer is set up each time on viewWillAppear means that whenever your view appears, you're creating a new timer (and leaking the old one) which will fire 60 seconds after creation.
If your view disappears and reappears multiple times, you're going to have multiple timers all firing the same method at completely random intervals.
You need to manage the timer properly. If you want it to start when the view is first created and keep ticking/firing even when the view is not shown, then you need to create it during init, or viewDidLoad, and then be sure to stop it when you dealloc or viewDidUnload.
If you want your timer to only tick/fire when the view is the current view, then you need to ensure you're managing stopping and starting the timer appropriately on viewDidAppear and viewWillDisappear.
Also, as Williham Totland said in his answer, NSTimer shouldn't be relied upon for exact timing. This is also stated in the documentation:
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.
In this case, with a time span of 60 seconds, it shouldn't be a problem that the timer is not exact, I think the issues you're seeing are because the timer isn't being managed properly.
The iPhone is a lot of things; and a neat device, however; just like any other computer, a precision timepiece it is not. However, it seems as if the method in question takes an NSTimeInterval, which is a double. You might want to change that to 60.0.
If you want your timer to only
tick/fire when the view is the current
view, then you need to ensure you're
managing stopping and starting the
timer appropriately on viewDidAppear
and viewWillDisappear.
Thanks for this info, even though I'm not the OP of this thread I was looking for an answer for a similar issue. I was scratching my head for few days, searched all over the internet but I couldn't find the answer. Finally I found this thread. This is a valuable info for me.