objective c - NSNotificationCenter: lista de observadores?
objective-c cocoa (6)
¿Es posible obtener la lista de observadores (objetos y selectores) para un nombre de notificación dado? (NSNotificationCenter)
¿Has probado la propiedad observationInfo
de NSObject?
observationInfo
Returns a pointer that identifies information about all of the observers that are registered with the receiver.
(iOS 9, Swift 3) Si desea saber qué observadores están actualmente registrados en NotificationCenter
, rompa e imprima su descripción de depuración:
(lldb) e print(NotificationCenter.default.debugDescription)
Cada línea de la salida contendrá Nombre (Notificación) , Objeto , Observador , Opciones . Las llamadas múltiples a NotificationCenter.default.addObserver
con algún NSNotification.Name
darán como resultado múltiples entradas en esta lista.
NÓTESE BIEN. Si bien esto podría ser una información útil cuando se realiza la depuración, no recomendaría administrar observadores en tiempo de ejecución utilizando esta salida.
(fuente: answer basada en useyourloaf )
Creé una categoría en NSNotificationCenter y modifiqué el método addObserver ::::.
Esto es solo para la depuración y nunca debe estar en el código de producción, ya que llevará a la retención de ciclos.
@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
En lugar de usar NSNotificationCenter, puede probar este ObserversCenter . Y usted puede obtener la lista de observadores.
Acerca de ObserverCenter:
- implementa un patrón de múltiples observadores como NSNotificationCenter;
- desacopla a los observados y observadores, por lo que no se conocen;
- puede suscribirse en una clave especificada;
- Puede llamar a la interfaz real al hacer una notificación.
No hay una API pública para consultar a NSNotificationCenter
sobre la lista de observadores actuales para cualquier objeto o notificación.
La respuesta anterior describe una solución y proporciona cierto nivel de detalle sobre la propiedad de los observadores, en una subclase de NSNotificationCenter
diseñada para recopilar y proporcionar dicha información.
Sin embargo, esta solución solo se puede utilizar con su propio código, que llamará a la subclase de NSNotiicationCenter
. ¿Qué pasa con otro código, tanto en el sistema como en las bibliotecas externas que usan el NSNotificationCenter
base para registrar / anular el registro de notificaciones?
Sugiero que, en lugar de NSNotificationCenter
subclases en NSNotificationCenter
, utilice un poco de ObjC de bajo nivel para cambiar las implementaciones del método del NSNotifictionCenter
original, reemplazándolas con nuestras propias implementaciones, que funcionarán más o menos como se describe en la respuesta anterior, y llamarán a Implementaciones originales como último acto.
Aquí se explica cómo hacerlo: http://nshipster.com/method-swizzling/
Luego, puede estar seguro de obtener TODOS los observadores de alguna notificación y de que su código es portátil y utilizable con un código de terceros que utiliza directamente NSNotificationCenter
.
No creo que haya una manera (oficial) de recuperar la lista de observadores para un nombre de notificación dado desde NSNotificationCenter
. Sin embargo, puede crear una subclase de NSNotificationCenter
y luego anular los siguientes métodos:
-
+ defaultCenter
-
- addObserver:selector:name:object
-
- addObserverForName:object:queue:usingBlock:
-
- removeObserver:
-
- removeObserver:name:object
En las implementaciones de anulación de los métodos de instancia, usted debería hacer un seguimiento de los observadores para un nombre de notificación dado utilizando un diccionario. En cada método de instancia anulado, finalmente llamaría al NSNotificationCenter
respectivo de NSNotificationCenter
. Además, proporcionaría un método para recuperar su propia lista de observadores para el nombre dado, por ejemplo:
- (id)observerForNotificationName:(NSString *)name
Sin embargo, hay dos problemas con este enfoque: primero, NSMutableDictionary
retendría a todos los observadores en una implementación ingenua, que probablemente no sea el mismo comportamiento que implementa NSNotificationCenter
. En segundo lugar, tendría que cambiar el código que obtiene el centro de notificaciones predeterminado mediante [NSNotificationCenter defaultCenter]
(o cualquier otra instancia de NSNotificationCenter
) para usar su subclase personalizada.
Tenga en cuenta que el primer problema es solucionable utilizando un CFDictionary
con devoluciones de llamada de referencia débiles, una clase contenedora con una referencia débil para el observador respectivo o, si se encuentra en un entorno de recolección de basura en Mac OS X, un NSHashTable
.