iphone screen time
NSNotificationCenter atrapa y rastrea todas las NSNotifications (4)
Hey Till: uso mucho las notificaciones y tuve algunos problemas serios al depurarlas también. Recientemente lancé una aplicación llamada Spark Inspector ( sparkinspector.com ) que simplifica un poco el proceso. Usted agrega un marco a su aplicación, y swizzles NSNotificationCenter para que pueda ver una tabla de todas las notificaciones enviadas y recibidas en su aplicación, con los rastreos de la pila donde fueron enviados y la lista de todos los métodos que los observaron. Sé que es cerca de tres años tarde, ¡pero puede ayudar!
Para una mejor comprensión de lo que sucede "bajo el capó", me encantaría hacer un seguimiento completo de las notificaciones que ocurren dentro de mi aplicación.
Ingenuo como soy, lo primero que intenté fue registrarme así:
En algún lugar de mi aplicación:
{
[...]
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(traceNotifications:) name:nil object:nil];
[...]
}
- (void)traceNotifications:(NSNotification *)notification
{
NSLog(@"received notification %@", [notification name]);
}
Realmente recibo una serie de notificaciones de esa manera. Pero en algún punto la aplicación falla. El seguimiento de la pila muestra que se está estrellando con EXC_BAD_ACCESS en realizeClass, lo que, según mi experiencia, indica que algo se llama después de su desasignación. Sin embargo, mi objeto de observación todavía está vivo, su desasignador no ha sido llamado (todavía).
Lo siguiente que probé fue establecer un punto de interrupción hacia -[NSNotificationCenter postNotification:]
y luego ejecutar po {NSNotification *}($ebp+16)
dentro de la consola gdb cada vez que mi punto de interrupción queda atrapado. Eso reveló algunas notificaciones, pero no todas las que estoy esperando / esperando. Por ejemplo, mi aplicación maneja los cambios de orientación correctamente, pero no veo ninguna notificación atrapada al reorientar el dispositivo (en el simulador).
¿Qué me estoy perdiendo? ¿Hay alguna forma (por ejemplo, una herramienta) para observar de manera confiable un NSNotificationCenter?
Gracias por cualquier pista.
La única solución que obtuve para trabajar fue usar puntos de interrupción.
__CFXNotificationPost_old
un punto de interrupción en __CFXNotificationPost_old
(CoreFoundation) y lo agrupé con un comando de depurador po {NSNotification *}($ebp+12)
. Todo esto es muy factible dentro de la GUI de Xcode:
- haga clic en "Ejecutar" en el menú de la aplicación Xcode (parte superior de la pantalla)
- seleccione "depurador"
- dentro de la ventana del depurador, haga clic en "Mostrar puntos de interrupción"
- haga clic en la línea "Ingresar nombre-símbolo" e ingrese "__CFXNotificationPost_old"
- haga clic en el "+" en el lado derecho
- seleccione "Comando del depurador" en esa lista desplegable
- ingrese "po {NSNotification *} ($ ebp + 12)
- (también puede querer activar el registro marcando la casilla de verificación "Log" en la parte inferior)
- ejecuta tu aplicación en una sesión de simulación-depuración desde Xcode
La aplicación detendrá su ejecución cada vez que se publique una NSNotification y la mostrará dentro de la consola gdb.
Intenté crear un punto de rastreo dentro de gdb, pero fracasé porque las acciones de punto de rastreo dentro de Xcode gdb parecen estar defectuosas, o tal vez soy demasiado estúpido para hacer que funcionen.
También traté de crear un script de Dtrace de instrumentos personalizado, pero fallé porque mi Dtrace Karate simplemente no es lo suficientemente fuerte.
Si logra obtener alguna de las últimas opciones para trabajar, continúe y publíquelas como una respuesta alternativa. Le votaré y las marcaré como la favorita.
ACTUALIZAR
Después de esta pregunta, encontré la manera correcta de atrapar todas las notificaciones en el nivel CoreFoundation.
Así es como se puede hacer:
void MyCallBack (CFNotificationCenterRef center,
void *observer,
CFStringRef name,
const void *object,
CFDictionaryRef userInfo)
{
NSLog(@"name: %@", name);
NSLog(@"userinfo: %@", userInfo);
}
CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(),
NULL,
MyCallBack,
NULL,
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
Realmente me siento un poco avergonzado de no haber mirado más de cerca la interfaz de CoreFoundation antes.
Para propósitos de depuración, encuentro que un punto de interrupción es realmente mejor que agregar código al proyecto. Sin embargo, la solución de @Till no pareció funcionar para mí. Encontré otra solución en línea y la modifiqué un poco.
Punto de ruptura simbólico
- Símbolo :
-[NSNotificationCenter postNotificationName:object:userInfo:]
- Condición :
((NSRange)[$arg3 rangeOfString:@"^(_|NS|UI)" options:1024]).length == 0
- Acción : Comando del depurador
po $arg3
- Continuar automáticamente después de evaluar acciones.
Notas:
- La condición impide que se muestren las notificaciones que comienzan con
_
,NS
oUI
. -
1024
refiere aNSRegularExpressionSearch
, que no parece estar disponible para ese punto de interrupción. - Uso
.length == 0
lugar de.location == NSNotFound
porqueNSNotFound
parece evaluar a un valor diferente (-1
o(NSUInteger)18446744073709551615
) que el valor devuelto en este punto de interrupción (9223372036854775807
).
Sé que la pregunta publicada es antigua, pero pensé que respondería con un par de líneas de código.
Puede ver todas las notificaciones publicadas mientras su aplicación se ejecuta a través de este bloque:
[[NSNotificationCenter defaultCenter] addObserverForName:nil
object:nil
queue:nil
usingBlock:^(NSNotification *notification) {
NSLog(@"%@", notification.name);
}];
Agregue eso al método viewWillAppear de un controlador de vista apropiado. (Por supuesto, debe eliminar esto de su código cuando prepare su aplicación para cualquier tipo de distribución).
Además, asegúrese de añadir esto:
[[NSNotificationCenter defaultCenter] removeObserver:self];
A la vista del controlador de vista correspondiente, aparecerá el método de desaparición.
ACTUALIZACIÓN: Misma respuesta, pero en Swift:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
NSNotificationCenter.defaultCenter().addObserverForName(nil,
object: nil,
queue: nil) {
note in
print(note.name + "/r/n")
}
}
override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self)
super.viewWillDisappear(animated)
}