I'm using an NSTimer
like this:
timer = [NSTimer scheduledTimerWithTimeInterval:30.0f target:self selector:@selector(tick) userInfo:nil repeats:YES];
Of course, NSTimer
retains the target which creates a retain cycle. Furthermore, self
isn't a UIViewController so I don't have anything like viewDidUnload
where I can invalidate the timer to break the cycle. So I'm wondering if I could use a weak reference instead:
__weak id weakSelf = self;
timer = [NSTimer scheduledTimerWithTimeInterval:30.0f target:weakSelf selector:@selector(tick) userInfo:nil repeats:YES];
I've heard that the timer must be invalidated (i guess to release it from the run loop). But we could do that in our dealloc, right?
- (void) dealloc {
[timer invalidate];
}
Is this a viable option? I've seen a lot of ways that people deal with this issue, but I haven't seen this.
If you are using Swift here is an auto-cancelling timer:
https://gist.github.com/evgenyneu/516f7dcdb5f2f73d7923
The timer cancels itself automatically on
deinit
.It doesn't matter that weakSelf is weak, the timer still retains the object so there's still a retain cycle. Since a timer is retained by the run loop, you can (and I suggest to ) hold a weak pointer to the timer:
About invalidate you're way of doing is correct.
The proposed code:
has the effect that (i) a weak reference is made to self; (ii) that weak reference is read in order to provide a pointer to
NSTimer
. It won't have the effect of creating anNSTimer
with a weak reference. The only difference between that code and using a__strong
reference is that if self is deallocated in between the two lines given then you'll passnil
to the timer.The best thing you can do is create a proxy object. Something like:
Then you'd do something like:
Or even add a class method to BTWeakTimerTarget of the form
+scheduledTimerWithTimeInterval:target:selector:...
to create a neater form of that code. You'll probably want to expose the realNSTimer
so that you caninvalidate
it, otherwise the rules established will be: