web-dev-qa-db-ja.com

NSNotificationCenter:オブザーバーのリスト?

特定の通知名のオブザーバー(オブジェクトとセレクター)のリストを取得することは可能ですか? (NSNotificationCenter)

26
Antoine Rosset

(iOS 9、Swift 3)現在どのオブザーバーがNotificationCenterに登録されているかを知りたい場合は、デバッグの説明を中断して出力します。

(lldb) e print(NotificationCenter.default.debugDescription)

出力の各行には、(通知)名前オブジェクトオブザーバーオプションNotificationCenter.default.addObserverをいくつかのNSNotification.Nameとともに複数回呼び出すと、このリストに複数のエントリが作成されます。


注意。これはデバッグ時に役立つ情報になる可能性がありますが、この出力を使用して実行時にオブザーバーを管理することはお勧めしません。


(出典: answer に基づく seyourloaf

15
PDK

NSNotificationCenterから特定の通知名のオブザーバーのリストを取得する(公式の)方法はないと思います。ただし、NSNotificationCenterのサブクラスを作成してから、次のメソッドをオーバーライドすることはできます。

  • + defaultCenter
  • - addObserver:selector:name:object
  • - addObserverForName:object:queue:usingBlock:
  • - removeObserver:
  • - removeObserver:name:object

インスタンスメソッドのオーバーライド実装では、ディクショナリを使用して、特定の通知名のオブザーバーを追跡します。オーバーライドされた各インスタンスメソッドで、最終的にNSNotificationCenterのそれぞれのsuperメソッドを呼び出します。さらに、次のように、指定された名前のオブザーバーの独自のリストを取得するメソッドを提供します。

- (id)observerForNotificationName:(NSString *)name

ただし、このアプローチには2つの問題があります。1つは、NSMutableDictionaryがすべてのオブザーバーを単純な実装で保持することです。これは、おそらくNSNotificationCenterが実装する動作とは異なります。次に、カスタムサブクラスを使用するために、デフォルトの通知センターを取得するコードを[NSNotificationCenter defaultCenter](またはその他のNSNotificationCenterインスタンス)で変更する必要があります。

最初の問題は、弱参照コールバックを使用したCFDictionary、それぞれのオブザーバーへの 弱参照を使用したコンテナークラス を使用して解決できることに注意してください。または、ガベージコレクション環境にいる場合はMac OS X、NSHashTable

14
starbugs

オブジェクトまたは通知の現在のオブザーバーのリストについてNSNotificationCenterにクエリを実行するためのパブリックAPIはありません。

前の回答は、解決策の概要を示し、そのような情報を収集して提供するように設計されたNSNotificationCenterのサブクラスで、オブザーバーの所有権に関するある程度の詳細に行きます。

ただし、このソリューションは、NSNotiicationCenterのサブクラスを呼び出す独自のコードでのみ使用できます。通知の登録/登録解除にベースNSNotificationCenterを使用するシステムライブラリと外部ライブラリの両方の他のコードはどうですか?

NSNotificationCenterをサブクラス化する代わりに、低レベルのObjCを少し使用して、元のNSNotifictionCenterのメソッド実装をスウィズルし、独自の実装に置き換えることをお勧めします。これは、多かれ少なかれ機能します。前の回答で説明されており、最後の動作として元の実装を呼び出します。

これを行う方法は次のとおりです。 http://nshipster.com/method-swizzling/

そうすれば、通知のすべてのオブザーバーを確実に取得でき、コードは移植可能であり、NSNotificationCenterを直接使用するサードパーティのコードで使用できます。

5
Motti Shneor

NSNotificationCenterでカテゴリを作成し、addObserver ::::メソッドをスウィズルしました。

これはデバッグ専用であり、保持サイクルにつながるため、本番コードに含めることはできません。

@interface NSNotificationCenter (Tracking)
@property (nonatomic) NSMutableArray <NSDictionary *> * observers;
@end


#import <JRSwizzle/JRSwizzle.h>
@implementation NSNotificationCenter (Tracking)

+ (void)initialize {
    [super initialize];
    [self jr_swizzleMethod:@selector(addObserver:selector:name:object:)
                withMethod:@selector(SNaddObserver:selector:name:object:)
                     error:nil];
}

- (void)SNaddObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject {
    NSDictionary *obs = @{@"observer"   :observer,
                          @"selector"   :NSStringFromSelector(aSelector),
                          @"name"       :aName
                          };
    DDLogDebug(@"observer added : %@", obs);
    [[self observers] addObject:obs];
    [self SNaddObserver:observer selector:aSelector name:aName object:anObject];
}

- (NSMutableArray <NSDictionary *> *) observers{
    static NSMutableArray <NSDictionary *> * _observers = nil;
    if (!_observers) {
        _observers = [NSMutableArray new];
    }
    return _observers;
}

@end
1
Zayin Krige

NSNotificationCenterを使用する代わりに、これを試すことができます ObserversCenter 。そして、あなたはオブザーバーのリストを得ることができます。

ObserverCenterについて:

  1. nSNotificationCenterとしてマルチオブザーバーパターンを実装します。
  2. それは観察者と観察者を切り離すので、彼らはお互いを知りません。
  3. 指定したキーでサブスクライブできます。
  4. 通知を行うときに実際のインターフェースを呼び出すことができます。
1
Andrew