2010-06-10 10 views
28

Vi estas líneas en un proyecto de demostración, pero no pude entender por qué lo hizo.cuándo utilizar "willChangeValueForKey" y "didChangeValueForKey"?

[self willChangeValueForKey:@"names"]; 
[self didChangeValueForKey:@"names"]; 

Se llamó didChangeValueForKey inmediatamente después de willChangeeValueForKey. ¿Tiene algún sentido?

Además, ¿cuándo debería ser el momento adecuado para llamar a estos dos métodos? Muchas gracias! :)

Respuesta

48

Esto es, de hecho, un anti-patrón. No debe llamar al -willChangeValueForKey: seguido de -didChangeValueForKey: sin ningún cambio intermedio de propiedad real. En algunos casos, hacerlo puede enmascarar los problemas de KVO en otro lugar de su código y obligar a los observadores a actualizar su estado relacionado con la propiedad en cuestión. En última instancia, sin embargo, usted (o el autor del ejemplo que cita) debería arreglar el resto del código para que este antipatrón no sea necesario.

El uso correcto de -will|didChangeValueForKey: es cuando está modificando una propiedad sin utilizar accesodores/ajustadores compatibles con KVC de modo que el mecanismo KVO no notaría el cambio. Para un ejemplo artificioso, considerar la modificación de la variable de instancia respaldo para un atributo directa:

@interface Foo 
{ 
    int bar; 
} 
@end 

@implementation Foo 
- (void)someMethod 
{ 
    bar = 10; 
} 
@end 

MVA observadores que se habían inscrito para la notificación de los cambios en la propiedad bar no recibir notificación del cambio a bar en -someMethod. Para hacer el trabajo de la maquinaria de MVA, se podría modificar -someMethod:

- (void)someMethod 
{ 
    [self willChangeValueForKey:@"bar"]; 
    bar = 10; 
    [self didChangeValueForKey:@"bar"]; 
} 

Por supuesto, sería mejor utilizar una declaración @property y utilizar KVC compatible con descriptores de acceso/set (ya sean codificadas o @synthesized manualmente), pero esto es un ejemplo artificial

+0

¡Muchas gracias! – Frost

+0

Me encontré con el mismo problema. Aquí hay un poco más sobre KVO de Apple http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i – Dan

0
  • Si quiere hacer algo antes de que se cambie el valor, use willChangeValueForKey.
  • Si desea hacer algo justo después de que se cambie el valor, use didChangeValueForKey.

Editar: ignorarme, estaba leyendo demasiado rápido - Barry es :-) derecho

1

Aquellos tienen que ver con el control manual de la observación de valor clave. Normalmente, el sistema se ocupa de ello, pero te permite un poco de control. Mire esta documentación para comprender cuándo y cómo usarlos here.

1

De acuerdo con Barry. Acabo de encontrar el mismo problema. Aquí hay un caso de usar esos dos métodos. Declaro una propiedad de solo lectura. Entonces no puedo usar el acceso de la propiedad para cambiar el valor.

@property (nonatomic, readonly) BOOL var; 

Cuando quiero cambiar la "var", necesito llamar estos dos métodos manualmente. De lo contrario, los observadores no serán notificados.

self willChangeValueForKey:@"var"]; 
var = YES; 
[self didChangeValueForKey:@"var"]; 
+0

var = SÍ ganó t compilar. ¿Te refieres a self.var = YES (que tampoco se compila con readonly)? Si te refieres a _var = SÍ, eso compilará, pero como no estás utilizando el generador generado, no me sorprende que will/didChange no sea invocado. Yo usaría self.var = YES sin leerlo solo. –

+0

Sí. Quise decir _var = SÍ. Mi caso es cómo usar la llamada Will/didChange para notificar de forma manual. – yibuyiqu

-3

Publicando esto en julio de 2013, y ya no parece ser necesario llamar a will/didChangeValueForKey. Parece que se atiende automáticamente, incluso si tienes un setter personalizado.

+0

will/didChangeValueForKey sigue siendo necesario para informar a los observadores cuando un valor cambia * sin * usar setters. –

9

KVO funcionará correctamente con ajustadores personalizados para las propiedades; este siempre ha sido el caso para las clases derivadas de NSObject. La maquinaria en tiempo de ejecución busca una invocación del método setter relevante, e invoca implícitamente "willChangeValueForKey" antes de ejecutar el setter, luego llama implícitamente "didChangeValueForKey" después de que el setter finaliza.

Puede deshabilitar este comportamiento automático si desea tener un control más preciso sobre las notificaciones de KVO. Como se mencionó anteriormente, las propiedades de solo lectura cuyo valor cambia modificando el respaldo ivar, o cuyos valores se derivan por cálculo, son lugares donde usaría las notificaciones manuales (aunque hay un mecanismo, keyPathsAffectingValueFor, donde puede indicar al tiempo de ejecución que el el valor de una propiedad depende del cambio de otra propiedad, y enviará la notificación de cambio según corresponda.) Para deshabilitar el comportamiento automático por propiedad, ingrese un método de clase + (BOOL) automáticamente Notifica ObserviosOf y devuelve NO .

A menudo deshabilito las notificaciones automáticas de KVO, porque he encontrado que se genera una notificación KVO al invocar un setter, incluso si el valor de la propiedad se establece en el valor actual (por ejemplo, no hay cambio). Deseo para suprimir la notificación sin sentido por el bien de la eficiencia:

+ (BOOL)automaticallyNotifiesObserversOfMyProperty 
{ 
    return NO; 
} 

- (void)setMyProperty:(NSInteger)myProperty 
{ 
    if(_myProperty != myProperty) 
    { 
    [self willChangeValueForKey:@"myProperty"]; 
    _myProperty = myProperty; 
    [self didChangeValueForKey:@"myProperty"]; 
    } 
} 

Una buena discusión se puede encontrar en la cabecera NSKeyValueObserving.h, que puede desplazarse a por Cmd + clic en el nombre de los métodos "willChangeValueForKey" y "didChangeValueForKey "en XCode.

+0

¿Quiere decir '+ keyPathsForValuesAffecting ' en lugar de 'keyPathsAffectingValueFor'? – Mojo66

0

Tenga mucho cuidado al anular didChangeValueForKey:. Lo mejor es no hacerlo en absoluto. Pero si lo hace, asegúrese de llamar al super; de lo contrario, tendrá una pérdida de memoria como se muestra aquí: https://github.com/jfahrenkrug/KVOMemoryLeak

Cuestiones relacionadas