NSTimer disables dealloc in UIView
Asked Answered
H

3

9
@interface someview:UIView{
  NSTimer* timer;
}
@end

@implementation someview

-(void)dealloc{
  NSLog(@"dealloc someview");
  [timer invalidate];
  timer = nil;
}
-(void)runTimer{
//
}
-(void)someMethod{

  timer = [NSTimer timerWithTimeInterval:2.0f target:self selector:@selector(runTimer) userInfo:nil repeats:YES];
}

@end

Releasing someview will NOT call dealloc and the timer keeps on running.

If I comment out the "timer = [NSTimer schedule...." part, dealloc will be called. Which means all the other part of my code is working properly and the timer is the culprit. The runTimer method is empty, which means it's just the timer messing with me.

Habiliment answered 14/4, 2011 at 22:25 Comment(0)
P
14

NSTimer retains the target. Therefore, the timer must be invalidated before your view is dealloc'd.

Planetstruck answered 14/4, 2011 at 22:30 Comment(3)
In the superview's dealloc, i put "[someview killtimer] and [someview release], the timer got invalidated but the dealloc still doesn't get calledHabiliment
Then something else is retaining the view.Aspia
Don't know why the killtimer method i implemented didn't work the first time i tried it.. but it works nowHabiliment
E
23

I think the best solution when using an NSTimer inside of a UIView is to override the removeFromSuperview method;

- (void)removeFromSuperview
{
    [timer invalidate];
    timer = nil;

    [super removeFromSuperview];
}

The only thing to keep in mind here is that you need to ensure that timer is not a nil object because removeFromSuperview can also get automatically called from other UIView's super dealloc methods. You could wrap in a conditional to check.

Evered answered 19/5, 2011 at 18:54 Comment(1)
removeFromSuperview will send a release message to the view. so i think we can do it in dealloc itself.Penultimate
P
14

NSTimer retains the target. Therefore, the timer must be invalidated before your view is dealloc'd.

Planetstruck answered 14/4, 2011 at 22:30 Comment(3)
In the superview's dealloc, i put "[someview killtimer] and [someview release], the timer got invalidated but the dealloc still doesn't get calledHabiliment
Then something else is retaining the view.Aspia
Don't know why the killtimer method i implemented didn't work the first time i tried it.. but it works nowHabiliment
V
1

As mentioned above, Timers retain their targets. Until the timer is invalidated, there is a retain cycle between the timer and the view, so the view will not be deallocated.

I would invalidate the timer when it's removed from the view hierarchy by subclassing didMoveToSuperview, this gets called by the system when there is a View-Related Change (e.g superview changes). The 'removeFromSuperview' is only called when removeFromSuperview is called on UIView

- (void)didMoveToSuperview
{
    [super didMoveToSuperview];

    if (!self.superview)
    {
        [timer invalidate];
        timer = nil;
    }
}
Vocalism answered 18/12, 2013 at 15:28 Comment(1)
The problem is not necessarily caused by a retain cycle. Even if you have a weak (or no) reference to the timer, the timer will be retained by the run loop it's scheduled in.Aspa

© 2022 - 2024 — McMap. All rights reserved.