2012-01-13 2 views
0

これは私のパターンです:デリゲートにインスタンスが不要になったことを正しく通知する方法

1)SpecialViewはMessageViewを作成し、それに対する強い参照を保持します。

2)ユーザーがMessageView内のボタンをタップすると、メッセージがフェードアウトします。それから、MessageViewはそれが完全にフェードアウトしたことを、そのデリゲート、SpecialViewに伝えます。

3)SpecialViewがMessageViewをリリースしました。私は順番に、すぐMessageViewを解放デリゲートを呼んでいる最後の行で

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context { 
    [self.delegate messageViewFadedOut:self]; // delegate releases us... 
    // self maybe got deallocated... BOOM! 
    // now what? method of a zombie returns? stack freaks out? 
} // does it even return? 

問題は、このです。 -fadedOut:finished:context:コアアニメーションdidStopSelectorコールバックによって呼び出されます。

は私の恐怖はMessageViewインスタンスがすぐに-fadedOut前を割り当て解除しようとしているということです:終了:コンテキスト:非常に厄介なランダムなバグワンス・アポン・ア・タイム

を起こし、完全に返され、古いベテランプログラマは語りました私:あなたが座っている枝を切らないでください。

だからインスタンスは、このメソッドが戻るまで生き残ることを確認するために、私は、デリゲートを呼び出す前に保持-autorleaseダンスをした:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context { 
    //[[self retain] autorelease]; 
    [self.delegate messageViewFadedOut:self]; // delegate releases us... 
} 

しかし、ARCの下で、保持-autoreleaseの踊りは許可されませんもはや(移行ツールでは許可されません)、ARCシステムにこのようなことをさせる方法がないようです。

だから私が代わりにこの戦略を思い付いた:遅れperformSelectorがうまくいけば、この方法が完全に戻ることができます

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context { 
    [self.delegate performSelector:@selector(messageViewFadedOut:) withObject:self afterDelay:0]; 
} 

。私が知る限り、0の遅延は、セレクタがすぐにではなく次の実行ループの繰り返しで実行されることを保証します。

これは偽の可能性もあります。

他のオブジェクトを呼び出すメソッドが完全に返される前にオブジェクトが取得されてしまう可能性があるため、別のオブジェクトに最後の参照を破棄するように要求するこの問題を正しく解決するにはどうすればよいですか?スタックトレースゾンビのようなものがありますか?

ARCではどのようにこのような問題を解決する必要がありますか?

答えて

0

正直言って、私はretain-autoreleaseをエミュレートしようとするよりも、デリゲートメソッドが呼び出された時点で、あなたのメッセージビューへの参照が解放されているかどうか気にしないでください。 willFadeOut:メソッドのコントラクトは割り当て解除されないと想定されるかもしれませんが、fadedOut:またはdidFadeOut:メソッドはオブジェクトの割り当てを解除しても問題ありません。

deallocの方法では、恐ろしい乱雑なバグを避けるために、発生中のアクティブなフェードアウトアニメーションをキャンセルすることが理想的です(どこかの参照を保持)。そうすれば、deallocにはどのように、いつ届くかは気にしません。なぜなら、deallocは、オブジェクトの状態や視覚的異常が残ってしまうことを防ぐためにXを行うことを知っているからです。

だからあなたのソリューション(performSelector:withObject:afterDelay:)または多分GCDブロックを使用します。ほかに

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context 
{ 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 250 * NSEC_PER_MSEC), // 250ms 
        dispatch_get_current_queue(), 
        ^{ 
         [self.delegate messageViewFadedOut:self]; 
        }); 
} 

、ARCはちょうどautoreleaseすぐに、なぜあなたはそのコードセクションを何回の束をテストし、何が起こるか見ていないかもしれません? deallocにブレークポイントを置き、メソッドが戻る前に呼び出されているかどうかを確認してください。

+0

しかし、実際の問題は次のようなものです。オブジェクトの割り振り解除が完了する前に、オブジェクトの割り振り解除が発生した場合は危険ですか?上記のコードでわかるように、デリゲートを呼び出した後は何も起こりません。だから理論的には問題はありません。ゾンビが復帰しているという事実について、ランタイム・フリークを除いて。 – openfrog

+0

ああ。いいえ、私が知る限り危険ではありません。私は本番アプリでそれを自分で行い、悪影響はありませんでした。私はメソッドの最後の行でこれを行うしかありませんでした。さもなければ、 'dealloc'd' self'にアクセスしようとする何かがあるかもしれません。 – darvids0n

関連する問題