views:

452

answers:

2

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?

A: 

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.

Williham Totland
+2  A: 

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.

Jasarien
thanks for pointing out the problem, I am having headaches with troubleshooting the exc_bad_access when moving the [timer invalidate] into the viewdiddisappear method. ( I have moved the other init function of the timer to viewDidLoad as you suggested).
sfa
If you create the timer in `viewDidLoad` then you should invalidate it in `dealloc` or 'viewDidUnload`, not `viewDidDisappear`. Each time your view disappears, you'll be stopping and releasing the timer object, and since it isn't being recreated (`viewDidLoad` is only called when the view loads, not each time the view comes on screen), you're over releasing it, causing the bad access.When you create a timer using `scheduledTimer...` it returns a timer object that is retained by the runloop. When the timer is sent `invalidate` it is removed from the runloop and is released.
Jasarien
ohh, thank Jasarien, I have solved the issue! I put the timer in viewDidAppear and invalidate it in viewDidDisappear. The exc_bad_access infact come from other xml parser variables. Thank for your hint!
sfa