13

単一のオブジェクトの複数のイベントについて複数のオブザーバーが必要です(1対Nの関係)。

このタスクを実行するメカニズムは、によって提供されますNSNotificationCenter。私の問題に使用すると、メカニズムはかなりやり過ぎに見えます。

を使用せずに手動で行う方法NSNotificationCenter

- (void)addDelegate:(id<DelegateProtocol>)delegate;
- (void)removeDelegate:(id<DelegateProtocol>)delegate;

オブジェクトにオブザーバーを追加および削除します。

- (void)someEventFired:(NSObject<NSCopying> *)eventData
{
    for (id delegate in delegates) {
        NSObject *data = [eventData copy];
        [delegate someEventFired:data];
    }
}

このメカニズムは、オブジェクトが追加の文字列を共有する必要がなく、簡単に実装できます。

  • iOSフレームワークに1対Nのデリゲート(C#イベントなど)の公式パターンはありNSNotificationCenterますか?
  • いつ使用すべきNSNotificationCenterか、いつ使用すべきでないか?
  • ここで提案しているような実装をいつ使用する必要がありますか?
4

7 に答える 7

14

慣例により、デリゲートはおそらく1:1の関係にのみ使用する必要があります。このタイプの機能に1:Nの関係が本当に必要な場合は、次の2つのオプションがあります。

  1. あなたが言ったように、NSNotificationCenter
  2. Key-Value Observing(KVOとも呼ばれます)。

KVOは、オブジェクトの特定のプロパティがいつ変更されるかだけを気にする場合に適しています。それ以外の場合は、実際にの使用を検討する必要がありますNSNotificationCenter。特定のオブジェクトがそのオブジェクトをaddObserver:selector:name:object:メソッドに渡すことにより、その通知を投稿したときにのみ通知を受けることもできます。

AppleはNSNotification、同様のシナリオで使用します(、、、UITextFieldを含むUITextFieldTextDidBeginEditingNotification、に対して定義された通知UITextFieldTextDidChangeNotificationなどUITextFieldTextDidEndEditingNotification)。

于 2012-05-31T15:28:20.203 に答える
2

通知の使用はブロードキャストです。1人の送信者が情報を送信するだけで、これまでにチューニングした人はそれを受信します。ラジオ局のようにささいなことですが、チャンネルバックはありません(今のところ電話を忘れさせてください)

委任は別のものです。委任者に何かをするように要求するオブジェクトは、通常、その要求の結果を必要とします。したがって、委任は1対1の通信であり、委任ではなく、常にオブジェクトによって開始されます(オブジェクトは次のようなメソッドを持つことができます)。通信を開始するようにオブジェクトに通知するために呼び出すことができます[tableView reloadData]

したがって、送信者がデータを取り戻す必要がある場合、それは委任です。送信者がブロードキャスト後に何も気にしない場合は、通知を送信してください。

この状況に遭遇した場合は、委任が必要ですが、いくつかのオブジェクトがプロトコルを実装する必要があります。他のオブジェクトへの参照を保持し、送信者に代わってメソッドを呼び出す1つのデリゲートが必要です。または、ブロックを使用することもできます。

于 2012-05-31T15:32:21.417 に答える
1

提案されたソリューションは、NSNotificationCenterを使用するよりも単純でも、スレッドセーフでもありません。

ソリューションスレッドを安全にするには、forループのイベントディスパッチの実行中にデリゲート配列が変更されないようにするメカニズムを提供する必要があります。

ソリューションでは、クラスでデリゲート配列を維持する必要もあります。NotificationCenterを使用すると、デフォルトのセンターを使用するだけで済み、クラスにadd/removeメソッドを実装する必要はありません。代わりに、インスタンスは自分自身を登録して、最適と思われる通知(セレクター/ブロック、キュー、ソース)を受信できます。ソースクラスはこれらの詳細について心配する必要はありません。指定されたタイプの通知のソースとして自分自身を登録する必要があるだけです。ブロックを使用して通知を処理すると、非常に便利です。

通知センターの代わりに、ユースケースのニーズを満たす場合はKey-Value-Observingを使用することもできます。

最終的に、使用することを決定するメカニズムは、特定のユースケースにどの程度最適に適用されるかによって異なります。

于 2012-05-31T15:46:08.947 に答える
1

NSNotificationCenterは、あなたが提案していることに対してやり過ぎではなく、まさに正しい解決策です。これにより、監視対象のオブジェクトがそのオブザーバーを認識または気にする必要がなくなり、コードがより緩く結合され、よりクリーンになります。

通知名の文字列の共有は簡単で、オブザーバーがジョブを実行するためにこのヘッダーをインポートする必要がある場合は、共有定数ファイルまたは監視対象オブジェクトのヘッダーで定義できます。

于 2012-05-31T15:27:10.270 に答える
0

1対Nのデリゲート関係は意味がありません。見て

- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row

例えば。このオブジェクトに実際にn個のデリゲートがある場合はどうなりますか?すべてのデリゲートから取得したn個のビューのどれを使用するかをどのように決定する必要がありますか?代表者はまさにこの1対1の原則です。

NSNotificationCenterは正しいアプローチです。単に使用する

addObserver:selector:name:object:

それぞれ

postNotification:

これは間違いなくあまり多くのコードではありません。また、センターがすべての通話を処理するため、非常に簡単です。

于 2012-05-31T15:30:01.573 に答える
0

NSNotificationCenterは、システム全体のイベント(キーボードの外観や同様のイベントなど)以外には使用しないでください。その理由は、完全にタイプセーフではなく、すべてがすべてに依存する可能性があり、コンパイル時のチェックや使用状況の検索結果が得られなくなるためです。

私の意見では、KVOは、同様の欠点があるため、リッスンしているオブジェクトの外部の変更を監視するために使用しないでください(コンパイル時のチェックがなく、リスナーを適切に削除しないか、2回登録しないとクラッシュします)。

あなたが提起するaddDelegate/removeDelegateパターンは、型安全性とコンパイラーのチェックを維持し、依存関係を明示的にするという利点があるため、私の意見では完全に正しいパスです。唯一の問題は、保持サイクルを回避するために要素を弱く保持するコレクションタイプが必要なため、Appleがこのパターンにすぐに使用できるソリューションを提供していないことです。

ただし、BMNullableArrayとマクロを使用してこの問題を適切に解決するBMCommonsフレームワークのコードを参照してください。これらのマクロの定義については、 BMCore.hヘッダーを参照してください。

BM_LISTENER_METHOD_DECLARATION(protocol)
BM_LISTENER_METHOD_IMPLEMENTATION(protocol)

この実装により、同じリスナーが2回追加されることはなく、リスナーの保持が弱くなり、割り当て解除時に登録を解除するのを忘れてもクラッシュが発生しなくなります(ただし、プログラミングの間違いであるため、この条件をアサートでキャッチすることをお勧めします) )。

于 2017-11-24T08:20:36.470 に答える
-4

NSNotificationCenterは、情報についてデリゲートにクエリを実行する場合を除いて、デリゲートモデルではなく常に使用する必要があると言います(例-webView:shouldLoadRequest:)。デリゲートを使用しようとすると、より安定し、実装が容易になり、コードがよりクリーンになります。他の選択肢はブロックです。これは良いことかもしれませんが、メモリ管理に関しては苦痛になる可能性があります。

結局のところ、それはあなた次第ですが、NSNotificationCenterは、複数のオブザーバー機能の場合だけでも、ほとんどすべての状況で実行するための最良の方法だと思います。

于 2012-05-31T15:27:03.177 に答える