ransomweaver
ransomweaver

Reputation: 492

NSTimer, to retain or not to retain

This is something that has puzzled me for awhile.

I have a NSTimer, added to the currentRunLoop, and if I don't retain it, it crashes.

NSTimer *timer = [[NSTimer timerWithTimeInterval:60.0 target:self selector:@selector(tryUnion:) userInfo:nil repeats:NO] retain];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

I have read that I don't need to retain it, as addTimer to the NSRunLoop does that.

later I invalidate and release (if I don't retain above, I don't release below- that's the crashing case):

- (void) tryUnion:(NSTimer*)aTimer {
[aTimer invalidate];
[aTimer release];
}

My questions are 1) How should I write this, if its possible to do what i've done without the retain/release. 2) analyze flags this or a potential leak of the object in "timer". As written here, is there the possibility of leaks, or is it just that analyzer isn't smart enough to know that there is a release in the function called by the timer?

Upvotes: 4

Views: 2591

Answers (3)

zpasternack
zpasternack

Reputation: 17898

The rule is, don't release it if you didn't retain it. Here is a similar question which talks about that. So in your example code I would suggest not retaining it, and not releasing it.

But that's not your issue. Your issue is that you've created a non-repeating timer. You don't need to invalidate those, they invalidate themselves after they fire. From the NSTimer docs:

repeats
If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires.

So you should neither retain/release that timer, nor invalidate it. Fire and forget.

As an aside, if you use scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:, the adding of the timer to the runloop is done for you as well. So your whole thing would be like:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(tryUnion:) userInfo:nil repeats:NO];

Your timer function doesn't need to do anything with aTimer, just do whatever thing your timer is supposed to do; the timer will be invalidated and released without further intervention.

Upvotes: 4

Nick Bedford
Nick Bedford

Reputation: 4435

Well you're right in that the NSTimer shouldn't have to be retained. The class method +(NSTimer *)timerWithInterval should, by rule, autorelease it's reference.

But NSTimer's invalidate message removes itself from the NSRunLoop and that releases it's reference (the only one left at the time). Your second [aTimer release] call is the cause of the crash.

Upvotes: 1

enamrik
enamrik

Reputation: 2312

Calling invalidate on a timer releases it so you don't need to have another release statement. See the docs here

Upvotes: 1

Related Questions