特定の通知名のオブザーバー(オブジェクトとセレクター)のリストを取得することは可能ですか? (NSNotificationCenter)
(iOS 9、Swift 3)現在どのオブザーバーがNotificationCenter
に登録されているかを知りたい場合は、デバッグの説明を中断して出力します。
(lldb) e print(NotificationCenter.default.debugDescription)
出力の各行には、(通知)名前、オブジェクト、 オブザーバー、オプション。 NotificationCenter.default.addObserver
をいくつかのNSNotification.Name
とともに複数回呼び出すと、このリストに複数のエントリが作成されます。
注意。これはデバッグ時に役立つ情報になる可能性がありますが、この出力を使用して実行時にオブザーバーを管理することはお勧めしません。
(出典: answer に基づく seyourloaf )
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
。
オブジェクトまたは通知の現在のオブザーバーのリストについてNSNotificationCenter
にクエリを実行するためのパブリックAPIはありません。
前の回答は、解決策の概要を示し、そのような情報を収集して提供するように設計されたNSNotificationCenter
のサブクラスで、オブザーバーの所有権に関するある程度の詳細に行きます。
ただし、このソリューションは、NSNotiicationCenter
のサブクラスを呼び出す独自のコードでのみ使用できます。通知の登録/登録解除にベースNSNotificationCenter
を使用するシステムライブラリと外部ライブラリの両方の他のコードはどうですか?
NSNotificationCenter
をサブクラス化する代わりに、低レベルのObjCを少し使用して、元のNSNotifictionCenter
のメソッド実装をスウィズルし、独自の実装に置き換えることをお勧めします。これは、多かれ少なかれ機能します。前の回答で説明されており、最後の動作として元の実装を呼び出します。
これを行う方法は次のとおりです。 http://nshipster.com/method-swizzling/
そうすれば、通知のすべてのオブザーバーを確実に取得でき、コードは移植可能であり、NSNotificationCenter
を直接使用するサードパーティのコードで使用できます。
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
NSNotificationCenterを使用する代わりに、これを試すことができます ObserversCenter 。そして、あなたはオブザーバーのリストを得ることができます。
ObserverCenterについて: