35

是否可以获得给定通知名称的观察者列表(对象和选择器)?(NSNotificationCenter)

4

7 回答 7

27

(iOS 9, Swift 3) 如果你想找出当前注册了哪些观察者NotificationCenter,打破并打印它的调试描述:

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

输出的每一行都将包含(Notification) NameObjectObserverOptions。多次调用NotificationCenter.default.addObserverwith someNSNotification.Name将导致此列表中有多个条目。


注意。虽然这可能在调试时证明是有用的信息,但我不建议在运行时使用此输出管理观察者。


(来源:基于useyourloaf的答案

于 2017-05-14T14:30:38.073 回答
15

我认为没有一种(官方)方法可以从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.

于 2012-04-27T07:54:58.877 回答
5

没有公共 API 可以查询NSNotificationCenter任何对象或通知的当前观察者列表。

NSNotificationCenter先前的答案概述了一个解决方案,并在旨在收集和提供此类信息的子类中详细介绍了观察者的所有权。

但是,此解决方案只能与您自己的代码一起使用,该代码将调用NSNotiicationCenter. 系统和外部库中使用基础NSNotificationCenter注册/注销通知的其他代码呢?

我建议不要使用子类化NSNotificationCenter,而是使用一些低级 ObjC 来调整 original 的方法实现NSNotifictionCenter,用我们自己的实现替换它们,这将或多或少如上一个答案中描述的那样工作,并将调用原始实现作为他们的最后一幕。

以下是如何做到这一点:http: //nshipster.com/method-swizzling/

然后,你可以确保你得到了一些通知的所有观察者,并且你的代码是可移植的,并且可以与直接使用NSNotificationCenter.

于 2014-10-21T13:15:09.477 回答
1

你可以试试这个ObserversCenter,而不是使用 NSNotificationCenter 。你可以得到观察者的名单。

关于观察中心:

  1. 它实现了一个多观察者模式作为 NSNotificationCenter;
  2. 它将观察者和观察者解耦,因此他们彼此不认识;
  3. 您可以订阅指定的密钥;
  4. 您可以在发出通知时调用真实接口。
于 2015-03-03T05:53:21.170 回答
1

我在 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
于 2016-01-09T11:11:02.757 回答
1

与@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可能是必要的。

于 2020-12-10T14:55:03.913 回答
-2

你试过observationInfoNSObject的属性吗?

observationInfo
Returns a pointer that identifies information about all of the observers that are registered with the receiver.
于 2014-11-14T07:13:07.773 回答