Rick van der Linde
Rick van der Linde

Reputation: 2591

How to correctly invalidate my timer in NSRunLoop

I get information from a server in my app with a secondsToEnd value and I start a counter after I've received this information.

My project contains a scrollview, so to get around locking my timer due to scrolling around I add the timer to the NSRunLoop in the following way:

[[NSRunLoop currentRunLoop] addTimer:timer
                             forMode:NSRunLoopCommonModes];

I made a NSTimer property called, how original, timer and this is the whole snippet of my startTimer function:

- (void)startTimer
{
    if (_timer || [_timer isValid]) [_timer invalidate], _timer = nil, [_timer release];

    NSTimer * timer = [[NSTimer alloc] initWithFireDate:[NSDate date]
                                               interval:1.0
                                                 target:self
                                               selector:@selector(timer:)
                                               userInfo:nil
                                                repeats:YES];

    [[NSRunLoop currentRunLoop] addTimer:timer
                                 forMode:NSRunLoopCommonModes];

    [self setTimer:timer];
    [timer release];
}

The reason for the check to invalidate in the start method is because after the secondsToEnd value hits 0, I receive a new one and I call startTimer again.

And in my dealloc method I have this:

if (_timer || [_timer isValid]) [_timer invalidate], _timer = nil, [_timer release];

But it doesn't get invalidated? What am I doing wrong?

Upvotes: 1

Views: 3185

Answers (2)

progrmr
progrmr

Reputation: 77191

What order do these comma separated statements execute in? What happens if _timer is nil when you call invalidate or when you call release?

if (_timer || [_timer isValid]) [_timer invalidate], _timer = nil, [_timer release];

Try this instead, there is no need to check whether _timer is already nil. If it was nil then the method call does nothing.

if ([_timer isValid]) {
    [_timer invalidate];
}
[_timer release];

In the dealloc method there is no need to set _timer = nil, its storage is gone after this method ends.

Upvotes: 3

Kay
Kay

Reputation: 13146

You should first call [timer release] and then timer = nil. Same in dealloc method. The dealloc method might no get called immediately if outer objects are in autrelease pools. In these cases it is called when the system decides to drop your object finally. So it may take some time (if you set a breakpoint).

BTW I would suggest to avoid comma syntax and use blocks within curly braces instead. It's far more easier to read.

Upvotes: 1

Related Questions