私は、ナビゲーションコントローラにプッシュ/ポップされる異なるビューコントローラがCoreAnimationシーケンスを登録することができ、プッシュされたコントローラのライフタイムを通じて異なる時間にこれらのシーケンスがトリガされるアプリケーションに取り組んでいます。Instrumentsは報告しています。NSMallocBlocks(別名ブロックオブジェクト)が漏れていますが、本当ですか?
私がコントローラを押すたびに、私はブロックオブジェクト(各アニメーションブロックごとにプッシュするたびに32バイトのリーク)が漏れていると報告しています。しかし、私はどこに漏れているのかわかりません。これは、関連するコードです:ありシングルトンAnimationFactoryは、この方法は、とりわけ、
あります:
- (void)registerAnimationBlock:(int(^)(NSArray*, NSDictionary*))animationBlock forKey:(NSString*)key
{
[self.animationBlocks setObject:[animationBlock copy] forKey:key];
[animationBlock release];
}
そして、ナビゲーションコントローラのスタックにプッシュされ、別のビューコントローラは、それらの異なるアニメーションを登録しますこのようなコードを有する配列は、例えば:
- (void)setupCommonAnimations
{
int(^animationBlock)(NSArray*,NSDictionary*);
/************************************************************************************************************************/
// Move stuff up
/************************************************************************************************************************/
animationBlock =
^(NSArray* layers, NSDictionary* parameters)
{
CGFloat timeOffset = [[parameters objectForKey:@"timeOffset"] floatValue];
CABasicAnimation* a;
CABasicAnimation* a2 = [CABasicAnimation animationWithKeyPath:@"opacity"];
a2.fromValue = [NSNumber numberWithFloat:0.];
a2.toValue = [NSNumber numberWithFloat:1.];
CAAnimationGroup* g = [CAAnimationGroup animation];
g.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
g.fillMode = kCAFillModeBoth;
g.removedOnCompletion = NO;
g.duration = .4;
[CATransaction begin];
[CATransaction setCompletionBlock:
^{
for(CALayer *layer in layers)
layer.opacity = 1;
}];
for(CALayer *layer in layers)
{
a = [CABasicAnimation animationWithKeyPath:@"position.y"];
a.fromValue = [NSNumber numberWithFloat:1024 + layer.frame.size.height/2];
a.toValue = [NSNumber numberWithFloat:layer.frame.origin.y + layer.frame.size.height/2];
g.animations = [NSArray arrayWithObjects:a,a2, nil];
g.beginTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil] + timeOffset;
[layer addAnimation:g forKey:nil];
timeOffset += .2;
}
[CATransaction commit];
return 0;
};
[[AnimationFactory sharedFactory] registerAnimationBlock:animationBlock forKey:@"StuffUpAnimation"];
/************************************************************************************************************************/
// Sequential Fade-in
/************************************************************************************************************************/
animationBlock =
^(NSArray* layers, NSDictionary* parameters)
{
CGFloat timeOffset = [[parameters objectForKey:@"timeOffset"] floatValue];
CABasicAnimation* a2 = [CABasicAnimation animationWithKeyPath:@"opacity"];
a2.fromValue = [NSNumber numberWithFloat:0.];
a2.toValue = [NSNumber numberWithFloat:1.];
a2.duration = .4;
a2.fillMode = kCAFillModeBoth;
a2.removedOnCompletion = NO;
[CATransaction begin];
[CATransaction setCompletionBlock:
^{
for(CALayer *layer in layers)
layer.opacity = 1;
}];
for(CALayer *layer in layers)
{
a2.beginTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil] + timeOffset;
[layer addAnimation:a2 forKey:nil];
timeOffset += .4;
}
[CATransaction commit];
return 0;
};
[[AnimationFactory sharedFactory] registerAnimationBlock:animationBlock forKey:@"SeqFadeInAnimation"];
上記の方法は、例えば、ビューコントローラのinitまたはviewWillAppearで呼び出されることになります。アニメーションを登録するためにanimationBlock変数を再利用しています。
コントローラをポップ取得したときに最後に、それはそののdeallocシーケンスの一部として、以下を呼び出します:
- (void)cleanupAnimations
{
[[AnimationFactory sharedFactory] removeAnimationBlockForKey:@"SeqFadeInAnimation"];
[[AnimationFactory sharedFactory] removeAnimationBlockForKey:@"StuffUpAnimation"];
}
楽器によると、私は私がやるたびに漏れる:
[[AnimationFactory sharedFactory] registerAnimationBlock:animationBlock forKey:@"StuffUpAnimation"];
、最初のコードスニペットから、
[self.animationBlocks setObject:[animationBlock copy] forKey:key];
[animationBlock release];
ND:
- 私はビューコントローラ
- にスタックブロックを作成していますが、それのヒープコピーを作成し、シングルトン、それを渡して、可変辞書や通話に格納それは増加のバランスを取るためにリリースブロックのカウントを保持する。
- 元のスタックブロックは、それが宣言されたビューコントローラのメソッドがスコープ外になると、存在しなくなります。
- ブロックの囲み範囲から何も参照していないので、自己または変数/オブジェクトを保持してはいけません。実行時にパラメータから作業することができます。
だから私は漏れがどこにあるのか分かりません。さらに、View Controllerがポップされたときに、animationBlocks配列からブロックを削除していますが、これを行う必要はありません。(完了するとすぐにメモリを再利用する以外に)次回は、同じView Controllerをプッシュすると、同じキーでアニメーションブロックを再登録し、既存のキーでsetObject:withKeyを呼び出すと、そのキーにハッシュされたオブジェクトにリリースが送信されます新しいオブジェクトをその場所に設定します。
私は何を見落としていますか?
実際には、私はリークが特定のアニメーションブロックで発生することに気付きました。私はself.viewなどを参照していたため、保持サイクルが発生しました。しかし、私は今あなたのコードで試してみましょう、それはちょうど保持サイクルを破るかもしれない原因となります。 – SaldaVonSchwartz
OK、保持サイクルは問題です。私は、アニメーションが完全に終わったときに自然にアニメーションが終了し、完成したアニメーションの 'animationsBlock'配列をクリアすると思ったと思います。 –
いいえ、ブロックは、たとえば戻り値に応じて再生または削除できます。しかし、あなたの答えはまだ正しいです:私はヒープのコピーではなくパラメータでリリースを呼び出していたので、私は辞書からブロックを削除しても漏れていました。 – SaldaVonSchwartz