Defeating NSTimer Retain Cycle
If you've done any coding with NSTimer and ARC you'll know the pain of having to manually invalidate your timer before its owner can be deallocated.
Typically, you'll have to have your object's parent reach into the object's inner workings and invalidate the timer at the appropriate time. This is inconvenient and breaks encapsulation.
I have a UITableViewCell which utilizes a NSTimer to keep track of energy regeneration, and I was determined to make it work without any outside intervention.
My solution was to utilize the UITableViewCell's willMoveToWindow: method like so:
- (void)willMoveToWindow:(UIWindow *)newWindow { [super willMoveToWindow:newWindow]; if (newWindow == (id)[NSNull null] || newWindow == nil) { [self stopTimer]; } else { [self refreshEnergy]; } } - (void)stopTimer { [timer invalidate]; timer = nil; } - (void)refreshEnergy { if (timer == nil) { timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(refreshEnergy) userInfo:nil repeats:YES]; } ... }
Now the UITableVIewCell automatically starts and stops the repeating timer as needed and deallocates correctly.
A note: You might try to simple use a weak reference to self in the NSTimer constructor but you'll find that the timer must be invalidated to deallocate correctly. This WON'T work:
__weak MyClass *weakSelf = self; timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:weakSelf selector:@selector(refreshEnergy) userInfo:nil repeats:YES];











