tags:

views:

263

answers:

3

I always have an class which needs to set up a timer for as long as the object is alive. Typically an UIView which does some animation.

Now the problem: If I strongly reference the NSTimer I create and invalidate and release the timer in -dealloc, the timer is never invalidated or released because -dealloc is never called, since the run loop maintains a strong reference to the target. So what can I do? If I cant hold a strong ref to the timer object, this is also bad because maybe I need a ref to it to be able to stop it. And a weak ref on a object is not good, because maybe i'm gonna access it when it's gone. So better have a retain on what I want to keep around.

How are you guys solving this? must the superview create the timer? is that better? or should i really just make a weak ref on it and keep in mind that the run loop holds a strong ref on my timer for me, as long as it's not invalidated?

+1  A: 

For views, I put relevant timers into viewControllers.

For other things which might go away on their own, I'd use the same strategy. The timer goes into a controller object, which itself refers (weakly) to the object which might go away on its own. The timer then prods the controlled object.

Oftentimes, though, I'm fine with having a strong reference to something. As long as it tells me before it goes away, I can null out my reference -- [nil anyMessage] succeeds ....

Joseph Beckenbach
+4  A: 

For timers in View Controllers, my practice is:

scheduledTimerWithTimeInterval in viewDidAppear:

then

invalidate it in viewWillDisapper:
ohho
+3  A: 

Treat the lifetime of the timer target as being on screen, not between init and dealloc.

For UIView do something like this:

-(void) willMoveToSuperview:(UIView *)newSuperview { [self runMyTimer:newSuperview != nil]; }

For UIViewController do something like this:

-(void) viewWillAppear:(BOOL)inAnimated { [self runMyTimer:YES]; }
-(void) viewDidDisppear:(BOOL)inAnimated { [self runMyTimer:NO]; }

Using something like this:

-(void) runMyTimer:(BOOL)inRun {
  if ( inRun ) {
    if ( !myTimer ) myTimer = [[NSTimer scheduled...] retain];
  } else {
    if ( myTimer ) {
      [myTimer invalidate];
      [myTimer release];
      myTimer = nil;
    }
  }
}

And for completeness you can call [self runMyTimer:NO] in dealloc.

drawnonward