Можно ли получить список наблюдателей (объектов и селекторов) для данного имени уведомления? (NSNotificationCenter)
NSNotificationCenter: список наблюдателей?
Ответ 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.