是否可以获得给定通知名称的观察者列表(对象和选择器)?(NSNotificationCenter)
7 回答
(iOS 9, Swift 3) 如果你想找出当前注册了哪些观察者NotificationCenter
,打破并打印它的调试描述:
(lldb) e print(NotificationCenter.default.debugDescription)
输出的每一行都将包含(Notification) Name、Object、Observer、Options。多次调用NotificationCenter.default.addObserver
with someNSNotification.Name
将导致此列表中有多个条目。
注意。虽然这可能在调试时证明是有用的信息,但我不建议在运行时使用此输出管理观察者。
(来源:基于useyourloaf的答案)
我认为没有一种(官方)方法可以从NSNotificationCenter
. 但是,您可以创建一个子类,NSNotificationCenter
然后覆盖以下方法:
+ defaultCenter
- addObserver:selector:name:object
- addObserverForName:object:queue:usingBlock:
- removeObserver:
- removeObserver:name:object
在实例方法的重写实现中,您将使用字典跟踪给定通知名称的观察者。在每个被覆盖的实例方法中,您最终都会调用NSNotificationCenter
's 各自的super
方法。此外,您将提供一种方法来检索您自己的给定名称的观察者列表,例如:
- (id)observerForNotificationName:(NSString *)name
然而,这种方法有两个问题:首先,NSMutableDictionary
将所有观察者保留在一个幼稚的实现中,这可能不是相同的行为NSNotificationCenter
实现。其次,您必须更改通过[NSNotificationCenter defaultCenter]
(或任何其他NSNotificationCenter
实例)获取默认通知中心的代码,以便使用您的自定义子类。
请注意,第一个问题可以使用CFDictionary
带有弱引用回调的 a、带有对相应观察者的弱引用的容器类来解决,或者,如果您处于 Mac OS X 上的垃圾收集环境中,则可以使用NSHashTable
.
没有公共 API 可以查询NSNotificationCenter
任何对象或通知的当前观察者列表。
NSNotificationCenter
先前的答案概述了一个解决方案,并在旨在收集和提供此类信息的子类中详细介绍了观察者的所有权。
但是,此解决方案只能与您自己的代码一起使用,该代码将调用NSNotiicationCenter
. 系统和外部库中使用基础NSNotificationCenter
注册/注销通知的其他代码呢?
我建议不要使用子类化NSNotificationCenter
,而是使用一些低级 ObjC 来调整 original 的方法实现NSNotifictionCenter
,用我们自己的实现替换它们,这将或多或少如上一个答案中描述的那样工作,并将调用原始实现作为他们的最后一幕。
以下是如何做到这一点:http: //nshipster.com/method-swizzling/
然后,你可以确保你得到了一些通知的所有观察者,并且你的代码是可移植的,并且可以与直接使用NSNotificationCenter
.
你可以试试这个ObserversCenter,而不是使用 NSNotificationCenter 。你可以得到观察者的名单。
关于观察中心:
- 它实现了一个多观察者模式作为 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
这适用于 Xcode 12,在旧版本上,debugDescription
可能是必要的。
你试过observationInfo
NSObject的属性吗?
observationInfo
Returns a pointer that identifies information about all of the observers that are registered with the receiver.