2012-05-10 11 views
0

私は、ナビゲーションコントローラにプッシュ/ポップされる異なるビューコントローラが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:

  1. 私はビューコントローラ
  2. にスタックブロックを作成していますが、それのヒープコピーを作成し、シングルトン、それを渡して、可変辞書や通話に格納それは増加のバランスを取るためにリリースブロックのカウントを保持する。
  3. 元のスタックブロックは、それが宣言されたビューコントローラのメソッドがスコープ外になると、存在しなくなります。
  4. ブロックの囲み範囲から何も参照していないので、自己または変数/オブジェクトを保持してはいけません。実行時にパラメータから作業することができます。

だから私は漏れがどこにあるのか分かりません。さらに、View Controllerがポップされたときに、animationBlocks配列からブロックを削除していますが、これを行う必要はありません。(完了するとすぐにメモリを再利用する以外に)次回は、同じView Controllerをプッシュすると、同じキーでアニメーションブロックを再登録し、既存のキーでsetObject:withKeyを呼び出すと、そのキーにハッシュされたオブジェクトにリリースが送信されます新しいオブジェクトをその場所に設定します。

私は何を見落としていますか?

答えて

3

元のブロックではなく、作成したコピーをリリースする必要があります。あなたがする必要があります:

animationBlock = [animationBlock copy]; 
[self.animationBlocks setObject:animationBlock forKey:key]; 
[animationBlock release]; 
+0

実際には、私はリークが特定のアニメーションブロックで発生することに気付きました。私はself.viewなどを参照していたため、保持サイクルが発生しました。しかし、私は今あなたのコードで試してみましょう、それはちょうど保持サイクルを破るかもしれない原因となります。 – SaldaVonSchwartz

+0

OK、保持サイクルは問題です。私は、アニメーションが完全に終わったときに自然にアニメーションが終了し、完成したアニメーションの 'animationsBlock'配列をクリアすると思ったと思います。 –

+0

いいえ、ブロックは、たとえば戻り値に応じて再生または削除できます。しかし、あなたの答えはまだ正しいです:私はヒープのコピーではなくパラメータでリリースを呼び出していたので、私は辞書からブロックを削除しても漏れていました。 – SaldaVonSchwartz

関連する問題