先日、画面遷移時にメモリが開放されず、徐々にメモリ利用率が上昇する現象に苦しまされた。
Instrumentsで調べてみても、リークは見られなかった。何が問題だったのか。それはdispatch_after
を用いたループするアニメーションだった。
dispatch_after
や、NSRunLoop
、NSTimer
等を用いてループ処理を実行していると、ownerとなるオブジェクトが解放されようとしても、これらのオブジェクトが強参照するために、解放されないようだ。
今回実装していた物
UIImageView
のカスタムクラスの上に、UIImage
が乗っており、animationImages
とNSTimer
によって、フェードイン・アウトするアニメーションの挙動を実装した。
参考:iphone fading of images
元々の実装
これだと、ループが回り続け、ownerのオブジェクトは永遠に開放されない
NSTimer *timer = [NSTimer timerWithTimeInterval:4.0
target:self
selector:@selector(onTimer)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[timer fire];
対策後
NSTimerをpropertyとして持ち、Viewが消える時に、invalidate
し、解放する必要がある。
@interface JSKSwipeViewController ()
@property (nonatomic) NSTimer *timer;
@end
@implementation JSKSwipeViewController
- (void)startAnimation
{
_timer = [NSTimer timerWithTimeInterval:4.0
target:self
selector:@selector(onTimer)
userInfo:nil
repeats:YES];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
// stop animation and release
[self.timer invalidate];
self.timer = nil;
}