objective-c - español - cocoa framework
¿Para qué sirve el parámetro de contexto en la observación de valores clave? (1)
Espero que esta explicación no sea demasiado abstracta para entender.
Supongamos que creas una clase MyViewController
, que es una subclase de UIViewController
. No tienes el código fuente de UIViewController
.
Ahora decide hacer que MyViewController
use KVO para observar los cambios en la propiedad center
de self.view
. Así que debidamente te agregas a ti mismo como un observador:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.view addObserver:self forKeyPath:@"center" options:0 context:NULL];
}
- (void)viewDidDisappear:(BOOL)animated {
[self.view removeObserver:self forKeyPath:@"center"];
[super viewDidDisappear:animated];
}
El problema aquí es que no se sabe si UIViewController
también se registra como un observador del self.view
de self.view
. Si lo hace, entonces podría tener dos problemas:
- Es posible que te llamen dos veces cuando cambie el centro de la vista.
- Cuando se elimina como observador, también puede eliminar el registro KVO de UIViewController.
Necesita una forma de registrarse como observador que se distinga del registro KVO de UIViewController. Ahí es donde entra en UIViewController
el argumento de context
. UIViewController
pasar un valor de context
que esté absolutamente seguro de que UIViewController
no está utilizando como argumento de context
. Cuando anulas el registro, usas el mismo context
nuevamente para que solo elimines tu registro, no el registro de UIViewController
. Y en su observeValueForKeyPath:ofObject:change:context:
necesita verificar el context
para ver si el mensaje es para usted o para su superclase.
Una forma de asegurarse de utilizar un context
que nada más use es crear una variable static
en MyViewController.m
. Úselo cuando se registre y anule el registro, así:
static int kCenterContext;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.view addObserver:self forKeyPath:@"center" options:0 context:&kCenterContext];
}
- (void)viewDidDisappear:(BOOL)animated {
[self.view removeObserver:self forKeyPath:@"center" context:&kCenterContext];
[super viewDidDisappear:animated];
}
Luego, en su método observeValueForKeyPath:...
, observeValueForKeyPath:...
así:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
{
if (context == &kCenterContext) {
// This message is for me. Handle it.
[self viewCenterDidChange];
// Do not pass it on to super!
} else {
// This message is not for me; pass it on to super.
[super observeValueForKeyPath:keyPath ofObject:object
change:change context:context];
}
}
Ahora tiene la garantía de no interferir con el KVO de su superclase, si es que lo hace. Y si alguien hace una subclase de MyViewController
que también usa KVO, no interferirá con su KVO.
Tenga en cuenta también que puede usar un contexto diferente para cada ruta clave que observe. Luego, cuando el sistema le notifica un cambio, puede verificar el contexto en lugar de verificar la ruta de la clave. Probar la igualdad de punteros es un poco más rápido que verificar la igualdad de cadenas. Ejemplo:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
{
if (context == &kCenterContext) {
[self viewCenterDidChange];
// Do not pass it on to super!
} else if (context == &kBackgroundColorContext) {
[self viewBackgroundDidChange];
// Do not pass it on to super!
} else if (context == &kAlphaContext) {
[self viewAlphaDidChange];
// Do not pass it on to super!
} else {
// This message is not for me; pass it on to super.
[super observeValueForKeyPath:keyPath ofObject:object
change:change context:context];
}
}
¿Cuál es el uso del parámetro de contexto en el siguiente método que se usa para registrarse para notificaciones de valores clave? La documentación simplemente lo denota como un conjunto arbitrario de datos.
addObserver:self forKeyPath:@"selectedIndex" options:NSKeyValueObservingOptionNew context:nil
¿Puede alguien arrojar algo de luz cuál es el propósito detrás de esto ...