CAAnimationのdelegateには落とし穴があった。
UIKitのdelegate系はすべて弱参照だと思っていたが、
CAAnimationのdelegateに限っては強参照のようだ。
https://developer.apple.com/library/mac/#documentation/graphicsimaging/reference/CAAnimation_class/Introduction/Introduction.html
Important: The delegate object is retained by the receiver. This is a rare exception to the memory management rules described in Advanced Memory Management Programming Guide.
An instance of CAAnimation should not be set as a delegate of itself. Doing so (outside of a garbage-collected environment) will cause retain cycles.
NSTimerのターゲットアクションもそうだが、非常に気づきにくいメモリリークの原因である。
他にもこういうケースはありそうである。
また、ヘッダーをしっかり確認するというのは大切である。
CAAnimationの明示的アニメーションは、
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
等と設定しない限りはアニメーションの終了と同時にオブジェクトが消滅するが、
ループアニメーションの場合や、上の設定をした場合、自然には削除されない。
なので例えばViewController等でLayerをコントロールする場合、
ViewConroller -> View -> Layer -> ViewController(delegate)
という強参照ループが状況によってはあり得る
さてdelegateを使う場合今回のケースの対策だが、ごく単純に
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
/*ここで何か処理*/
anyLayer.delegate = nil;
}
としてみたが、理由は分からないが例外をはかれてしまった。
なので、
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
/*ここで何か処理*/
[anyLayer removeAllAnimations];
}
ということで対応ができた。
これは状況によってどのように循環参照を断ち切るのかは変わってきそうである。