11

私の現在のプロジェクトでは、いくつかのビュー コントローラー ( など)が、静的な NSOperationQueue で実行されるvcNSOperation オブジェクト ( など) を生成します。operation操作が待機中または実行中の場合、委譲 ( operation.delegate = vc、割り当てられていない、保持されていない) を介してビュー コントローラーに報告されます。

ただし、これらの操作には時間がかかる場合があり、その間にアプリはビュー コントローラーの割り当てを解除できます (ナビゲーション コントローラーのスタックからポップすることにより)。

ここまではすべて意図的です。静的な NSOperationQueue を含むクラスには操作に戻る方法があるため、View Controller は操作を保持しません。それらは alloc/init/autoreleased であり、キューに入れられます。

現在、これも問題を引き起こしています。ビュー コントローラーの割り当てが解除された後、NSOperation の強力なデリゲートを呼び出すと、不正なアクセス違反が発生します。私が理解していることから、この質問に記載されているように、ポインターのオブジェクトが割り当て解除されているかどうかを確認することはできません。

私が考えることができる 1 つの修正は、操作を保持し、dealloc で operation.delegate を nil に設定することです。しかし、追跡するために多くの追加のivar /プロパティが導入されるため、それは私の最も人気のない修正です。

したがって、私の質問は、この問題を回避する他の方法はありますか? もしそうなら、ここにスケッチしていただけますか?

乾杯、
EP。

解決策:私にとって最もうまくいったアプローチは、ギリアーノの答えをわずかに変えたものでした:

  • キュー マネージャーにすべてのデリゲート プロトコルを実装することは現実的ではありません (50 以上のメソッドを持つ 20 以上の異なるプロトコル)。そのため、直接デリゲートの割り当てを維持しました。私が変更したのは、割り当て呼び出しを行うクラスです。これは、以前は要求を作成したクラス (およびデリゲート) でしたが、現在はキュー マネージャーにオフロードされています。

  • キュー マネージャーは、デリゲートを操作に割り当てるだけでなく、デリゲートと操作のペアを追跡するために、可変のセカンダリ ディクショナリも保持します。

  • すべてのデリゲート インスタンスは[QueueManager invalidateDelegate:self]割り当て解除時にメソッドを呼び出し、デリゲートに属するリクエストを検索して nil します。次に、ディクショナリ操作/デリゲートのペアも削除され、操作の適切な割り当て解除が可能になります。

  • 最後に、KVOisFinishedが各操作のプロパティを監視することで、変更可能な dict がクリーンに保たれ、すべての操作保持カウントが終了後に実際に割り当て解除されるようになります。

これをクラックするために KVO を使用するためのヒントを提供してくれた Guiliano に感謝します!

4

3 に答える 3

7

アーキテクチャを見直して、各操作でデリゲートを使用する代わりに、キューを管理するクラス (QueueManager を想定) にデリゲートを移動することをお勧めします。

  • viewControllers に通知するために必要なメソッドを実装する QueueManagerDelegate を作成します。

  • QueueManager で、各 NSOperation の isFinished プロパティに KVO オブザーバーを追加します (操作をキューに追加する前にこれを行います;))

  • KVO 呼び出しのコールバックで、デリゲート メソッドを呼び出す必要があるのは、デリゲートが != nil の場合のみです。

  • QueueManager に無効化メソッドを追加し、UIViewController の dealloc メソッドでこのメソッドを呼び出します。

    -(void)invalidate { self->delegate = nil; }

KVO の更新が必要な場合: Kvo プログラミング ガイド

于 2011-05-06T16:40:23.063 に答える
0

ここでの最善のアドバイスは、このような状況を回避するためにアプリのアーキテクチャを確認することです。ただし、現在のコードを変更できない場合は、NSNotificationCenterを使用できます。ビューコントローラーの割り当てが解除されるたびに、通知を投稿できます。この通知は、NSOperationQueueホルダーによってキャッチされる必要があります。これは、割り当てが解除されたビューコントローラーのデリゲートをゼロにするための通知ハンドラーの単純なforeachサイクルです。トリックを行う必要があります。

于 2011-05-06T16:06:06.383 に答える
0

また、デリゲートが nil でない場合は、操作完了からのメッセージにも応答できることを確認する必要があります。respondsToSelectorこれは、すべての NSObject サブクラスが持つ関数を使用して行います。

私のプロジェクトでは、このチェックを NSObject のカテゴリに抽象化し、任意の数のオブジェクト引数でデリゲートを安全に呼び出せるようにしました。

- (void) dispatchSelector:(SEL)selector target:(id)target objects:(NSArray*)objects onMainThread:(BOOL)onMainThread {

if(target && [target respondsToSelector:selector]) { // Do your delegate calls here as you please } }

ここで完全な例を見ることができます: https://github.com/chaione/ChaiOneUtils/blob/master/Categories/NSObject-Dispatch.m

于 2011-05-06T16:40:01.120 に答える