iOSの、画面遷移時のメモリリークが止まらなかった話
先日、画面遷移時にメモリが開放されず、徐々にメモリ利用率が上昇する現象に苦しまされた。
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; }