I am creating an NSTimer in the createTimer method that I want to refer back to in the later cancelTimer method. To facilitate this I am taking ownersh
You need to invalidate before you release. After the timer has fire, you are the only one holding a retain on the timer. So when you call release, the timer deallocates. You then call invalidate on invalid memory and you crash.
You release before you call invalidate. That means by the time you call invalidate, you've already relinquished ownership of the timer. In practice, you end up calling invalidate on a deallocated timer instance.
What you should do is call invalidate before you call release. Since you are using a retained property, you can just set the property to nil:
// Schedule the timer.
self.walkTimer = [NSTimer scheduledTimerWith...];
// Cancel the timer.
[self.walkTimer invalidate];
self.walkTimer = nil;
It's important to keep in mind the Memory Management Rules of Objective-C — you own an object if you call alloc, copy or retain on it, and if you own an object, you have to eventually call release. In this case, setWalkTimer: retains the timer because the property is declared as retain — that means you own the timer and must call release on it down the road. The invalidate method does not count as relinquishing ownership of the timer.
When you schedule a timer, the run loop retains it, and when the timer fires or is invalidated, the run loop releases it. But really, you don't need to know that — it's an implementation detail. The call to release by invalidate is only to balance the retain when the timer was scheduled on the run loop.
self as the target of a repeating timer unless you are absolutely sure to know all the consequences(...otherwise the runtime drowns a kitten in leaked timers, targets and userInfos — or so goes the saying.)
Please read and re-read "Overview" in the NSTimer Class Reference and pay special attention to the last paragraph.
In a nutshell:
NSTimer instances are not reusable:
"Once invalidated, timer objects cannot be reused".So there is no point in retaining a scheduled timer in the first place.
If you need to hang on to it (e.g. in order to cancel it) use a non-owning (aka weak) reference to it.
Update:
For a thorough explanation, see my answer to your other question (it now has graphs — albeit as links only — and stuff).
Please consider the rest of this post (as well as many of my comments) as obsolete.
Your property becomes
@property (nonatomic, assign) NSTimer *walkTimer;
BTW:
-(void)cancelTimer {
[self setWalkTimer:nil]; // great, now [self walkTimer] returns nil so
[[self walkTimer] invalidate]; // here, you are calling [nil invalidate]
}
And since messaging nil is absolutely fine in Objective C, your crash miraculously vanishes...while your timer will happily continue to fire.
Edit
I've forgot to mention:
A timer wants a selector that takes one argument, which will be the timer that fired... Or is that just a typo?