Подтвердить что ты не робот

NSNotificationCenter: список наблюдателей?

Можно ли получить список наблюдателей (объектов и селекторов) для данного имени уведомления? (NSNotificationCenter)

4b9b3361

Ответ 1

Я не думаю, что есть (официальный) способ получить список наблюдателей для данного имени уведомления от NSNotificationCenter. Однако вы можете создать подкласс NSNotificationCenter, а затем переопределить следующие методы:

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

В переопределяющих реализациях методов экземпляра вы должны отслеживать наблюдателей для данного имени уведомления с помощью словаря. В каждом методе переопределенного экземпляра вы, наконец, вызываете NSNotificationCenter соответствующий метод super. Кроме того, вы бы предоставили метод для получения собственного списка наблюдателей для данного имени, например:

- (id)observerForNotificationName:(NSString *)name

Однако при таком подходе есть две проблемы: во-первых, NSMutableDictionary сохранит всех наблюдателей в наивной реализации, что, вероятно, не соответствует поведению NSNotificationCenter. Во-вторых, вам нужно будет изменить код, который получает центр уведомлений по умолчанию, с помощью [NSNotificationCenter defaultCenter] (или любого другого экземпляра NSNotificationCenter), чтобы использовать свой собственный подкласс.

Обратите внимание, что первая проблема разрешима с помощью CFDictionary со слабыми ссылочными обратными вызовами, контейнерный класс со слабой ссылкой соответствующему наблюдателю или, если вы находятся в среде сбора мусора в Mac OS X, NSHashTable.

Ответ 2

Нет публичного API для запроса NSNotificationCenter о списке текущих наблюдателей для любого объекта или уведомления.

В предыдущем ответе описывается решение и доходит до некоторого уровня детализации относительно владения наблюдателями в подклассе NSNotificationCenter, предназначенном для сбора и предоставления такой информации.

Однако это решение можно использовать только с вашим собственным кодом, который вызовет подкласс NSNotiicationCenter. Как насчет другого кода, как в системе, так и в внешних библиотеках, которые используют базу NSNotificationCenter для регистрации/регистрации на уведомления?

Я предлагаю вместо подкласса NSNotificationCenter, используя бит низкоуровневого ObjC для swegle реализации методов исходного NSNotifictionCenter, заменяя их собственными реализациями, которые будут работать более или менее, как описано в предыдущий ответ и будет вызывать исходные реализации как их последний акт.

Вот как это сделать: http://nshipster.com/method-swizzling/

Затем вы можете быть уверены, что получите ВСЕ наблюдателей за каким-либо уведомлением и что ваш код переносим и может использоваться с сторонним кодом, который напрямую использует NSNotificationCenter.

Ответ 3

(iOS 9, Swift 3) Если вы хотите узнать, какие наблюдатели зарегистрированы в настоящее время в NotificationCenter, отмените и распечатайте его описание отладки:

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

Каждая строка вывода будет содержать (Уведомление) Имя, Объект, Наблюдатель, Параметры. Несколько вызовов NotificationCenter.default.addObserver с некоторыми NSNotification.Name приведут к появлению нескольких записей в этом списке.


NB. в то время как это может оказаться полезной информацией при отладке, я бы не советовал управлять наблюдателями во время выполнения, используя этот вывод.


(источник: answer на основе useyourloaf)

Ответ 4

Вместо использования NSNotificationCenter вы можете попробовать ObserversCenter. И вы можете получить список наблюдателей.

Об ObserverCenter:

  • он реализует шаблон с несколькими наблюдателями как NSNotificationCenter;
  • он отделяет наблюдаемых и наблюдателей, поэтому они не знают друг друга;
  • вы можете подписаться на указанный ключ;
  • вы можете вызвать реальный интерфейс при создании уведомлений.

Ответ 5

Я создал категорию в NSNotificationCenter и swizzled метод 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

Ответ 6

Вы пробовали свойство observationInfo объекта NSObject?

observationInfo
Returns a pointer that identifies information about all of the observers that are registered with the receiver.