1

MyAppDelegateは、アクティブなウィンドウ コントローラのリストを維持して、ARC がそれらの割り当てを早期に解除しないようにします。したがって、次のような通知ハンドラーがあります。

- (void) windowWillClose: (NSNotification*) notification {
    [self performSelectorOnMainThread: @selector(removeWindowControllerInMainThread:)
        withObject: windowController
        waitUntilDone: NO];
}

- (void) removeWindowControllerInMainThread: (id) windowController {
    [windowControllers removeObject: windowController];
}

通知スレッドで処理を行うと、準備が整う前にコントローラーの割り当てを解除するリスクがあるため、メイン スレッドを使用します。

現在、これは非常にうまく機能します — 現在実行中のアニメーターがある場合を除きます。を通じて、いくつかの場所でアニメーターを使用しNSAnimationContextます。私はこの QAを見てきましたが、答えは受け入れられません。アニメーションを完成させるためだけにしばらく待つのは本当に手抜きで、動作する保証はありません。確かにそうではありません。現在のアニメーションの長さよりも大きな遅延があっても、を使用してみperformSelector:withObject:afterDelayましたが、それでもアニメーターは nil オブジェクトに対して実行されます。

このようなコントローラーのクリーンアップを行う好ましい方法は何ですか? 使用するのではなく、代わりに使用するNSAnimationContext方法があるのはどれですか?NSAnimationstopAnimation

4

2 に答える 2

2

まず、アニメーションの一部が無期限に (または非常に長時間) 実行される場合、それらを停止する方法が必要になります。

しかし、ビューの暗黙的なアニメーションのようなものについては、単純に補完メソッドを使用できます。

  self.animating=YES;
  [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
    [[v animator] setAlphaValue: 1];
} completionHandler:^{
    self.animating=NO;
}];

これで、アニメーションが実行されているかどうかをポーリングするだけで済み、実行されていない場合はウィンドウを閉じます。

ポーリングを行う良い方法の 1 つは、一定の遅延でタイマーを設定することです。アニメーションがまだ実行中の場合は、タイマーをリセットして別の間隔を待ちます。

または、完了ハンドラから通知を送信することもできます。

于 2013-02-17T19:30:49.207 に答える
2

私は使用していませんNSAnimationContext(常にこれを使用していましNSAnimationたが、主に歴史的な理由から)。しかし、これに似たものを管理するために私が好む一般的な方法は、短命の保持ループを作成することです。

マークの答えはまさに正しいアイデアですが、ポーリングは必須ではありません。完了ハンドラーで参照するという事実は、完了ハンドラーが実行される前に割り当てを解除できないことselfを意味します。self読んだことがあるかどうかは実際には問題ではありませんanimating。ARC は、完了ブロックが実行されるまでユーザーを維持する必要があります。これは、ブロックがユーザーを参照しているためです。

もう 1 つの同様の手法は、 を使用して自分自身をアニメーション コンテキストに関連付けることobjc_setAssociatedObjectです。これにより、完了ブロックが実行されるまで保持されます。完了ブロックでself、関連付けられたオブジェクトとして削除すると、自由に割り当てを解除できます。このアプローチの良いところは、 のような偽の追加プロパティを必要としないことですanimating

そしてもちろん、場合によっては適切な最後の絶望的な手段は、短命の自己参照を作成することです. 例えば:

- (void)setImmortal:(BOOL)imortal {
  if (immortal) {
    _immortalReference = self;
  }
  else {
    _immortalReference = nil;
  }
}

私はこの最後のオプションを推奨しているわけではありません。しかし、それが存在することを知ることは良いことであり、さらに重要なのは、なぜそれが機能するのかを知ることです.

于 2013-02-17T23:29:57.490 に答える