Question

I have a subclassed UIView which is not being deallocated. I know that only one class is creating an instance of my view. I have an NSTimer ivar in my view. If I comment out that timer and when I tap a cancel button that is on this view controller, dealloc in this view is called. If I don't comment out the timer, the dealloc is never called.

//CustomUIView
- (id) initWithFrame:(CGRect)frame 
{
    self = [super initWithFrame:frame];
    if (self) {
        _pollTimer = [[NSTimer scheduleTimerWithTimeInterval:0.2 target:self selector:@selector(onPollTimerFired:) userInfo:nil repeats:YES] retain];
    }
}

I want to keep a reference to this timer because there are times when I wish to pause the timer. Now, I could have a property on my view for the timer and in the dealloc method of the class that has a reference to my custom uiview, I could invalidate it before releasing said view. I don't really like this approach because I don't want to expose this timer to outside entities.

Anyone have any ideas?

Was it helpful?

Solution

NSTimer always retains its target. This has two implications:

  1. You shouldn't have the view (which is the timer's target) retain the timer, as this will create a cycle.

  2. Your view will never be deallocated so long as the timer remains active.

Instead, you should call invalidate on the timer whenever your view is done with it. Once this is done, the view will be deallocated when its reference count goes to zero.

Typically this happens when a view is removed from its superview; if you want it to keep using its timer until that happens and then get released, you can override removeFromSuperview to invalidate the timer and then call super.

OTHER TIPS

Edit:

In your -dealloc method, try this:

- (void) dealloc
{
    [_pollTimer invalidate];

    /*
        If not using ARC:
        [_pollTimer release], _pollTimer = nil;
        [super dealloc];
    */
}

You have forgotten to call super's implementation of -initWithFrame:! Whoops!

- (id) initWithFrame:(CGRect)frame 
{
    if ((self = [super initWithFrame:frame]))
    {
        _pollTimer = [[NSTimer scheduleTimerWithTimeInterval:0.2 target:self selector:@selector(onPollTimerFired:) userInfo:nil repeats:YES] retain];
    }
    
    return self;
}

This should work much better.

You should not retain the timer. Schedule the timer like this : _pollTimer = [NSTimer scheduleTimerWithTimeInterval:0.2 target:self selector:@selector(onPollTimerFired:) userInfo:nil repeats:YES]; and whenever you want to invalidate it: [_pollTimer invalidate]

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top