特定の通知名のオブザーバー(オブジェクトとセレクター)のリストを取得することは可能ですか?(NSNotificationCenter)
7 に答える
(iOS 9、Swift 3)現在登録されているオブザーバーを確認したい場合はNotificationCenter
、デバッグの説明を中断して印刷します。
(lldb) e print(NotificationCenter.default.debugDescription)
出力の各行には、(通知)Name、Object、Observer、Optionsが含まれます。を複数回呼び出すとNotificationCenter.default.addObserver
、NSNotification.Name
このリストに複数のエントリが作成されます。
NB。これはデバッグ時に役立つ情報になる可能性がありますが、この出力を使用して実行時にオブザーバーを管理することはお勧めしません。
(出典:useyourloafに基づく回答)
から特定の通知名のオブザーバーのリストを取得する(公式の)方法はないと思います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を使用する代わりに、このObserversCenterを試すことができます。そして、オブザーバーのリストを取得できます。
ObserverCenterについて:
- 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
@PDKの回答と同様に、po NotificationCenter.default
(または適切なインスタンス)はデバッグ情報を生成します。
<NSNotificationCenter:0x600000f84310>
Name, Object, Observer, Options
UIApplicationSimpleRemoteActionNotification, 0x7faac90069a0, 0x600000f84fc0, 1400
NSTextStorageDidProcessEditingNotification, 0x7faacd80d080, 0x600001808a00, 1400
com.apple.ManagedConfiguration.profileListChanged, 0x600000b0e280, 0x600000b0e280, 1400
UIApplicationDidBecomeActiveNotification, 0x7faac90069a0, 0x600000ff75d0, 1400
UIApplicationDidBecomeActiveNotification, 0x7faac90069a0, 0x600001880d00, 1400
これはXcode12で機能し、古いバージョンではdebugDescription
必要になる場合があります。
observationInfo
NSObjectのプロパティを試しましたか?
observationInfo
Returns a pointer that identifies information about all of the observers that are registered with the receiver.