Ambos son realmente bastante frágiles y para nada idénticos, dependiendo de lo que estén haciendo los clientes de la clase. Hacerlos idénticos es bastante fácil, ver más abajo, pero hacerlo menos frágil es más difícil. Tal es el precio de la inicialización lenta (y por qué generalmente trato de evitar la inicialización lenta de esta manera, prefiriendo tratar la inicialización de los subsistemas como parte de la administración general del estado de la aplicación).
Con el n. ° 1, está evitando el armador y, por lo tanto, cualquier cosa que observe el cambio no verá el cambio. Al "observar", me refiero específicamente a la observación de valores clave (incluidos los enlaces de cacao, que utiliza KVO para actualizar la IU automáticamente).
Con el n. ° 2, activará la notificación de cambio, actualizando la UI y de otra manera exactamente como si se llamara al sistema.
En ambos casos, tiene un potencial de recursión infinita si la inicialización del objeto llama al captador. Eso incluye si un observador solicita el valor anterior como parte de la notificación de cambio. No hagas eso.
Si va a utilizar cualquiera de los métodos, considere cuidadosamente las consecuencias. Uno tiene el potencial de dejar la aplicación en un estado incoherente porque un cambio de estado de una propiedad no notificó y el otro tiene el potencial de un punto muerto.
Es mejor evitar el problema por completo. Vea abajo.
tener en cuenta (recolección de basura en la herramienta de línea de comandos de cacao estándar:.
#import <Foundation/Foundation.h>
@interface Foo : NSObject
{
NSString *bar;
}
@property(nonatomic, retain) NSString *bar;
@end
@implementation Foo
- (NSString *) bar
{
if (!bar) {
NSLog(@"[%@ %@] lazy setting", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
[self willChangeValueForKey: @"bar"];
bar = @"lazy value";
[self didChangeValueForKey: @"bar"];
}
return bar;
}
- (void) setBar: (NSString *) aString
{
NSLog(@"[%@ %@] setting value %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), aString);
bar = aString;
}
@end
@interface Bar:NSObject
@end
@implementation Bar
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
{
NSLog(@"[%@ %@] %@ changed\n\tchange:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), keyPath, change);
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Foo *foo = [Foo new];
Bar *observer = [Bar new];
CFRetain(observer);
[foo addObserver:observer forKeyPath:@"bar"
options: NSKeyValueObservingOptionPrior | NSKeyValueObservingOptionNew
context:NULL];
foo.bar;
foo.bar = @"baz";
CFRelease(observer);
[pool drain];
return 0;
}
Esto no cuelgue Es expulsado:
2010-09-15 12:29:18.377 foobar[27795:903] [Foo bar] lazy setting
2010-09-15 12:29:18.396 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed
change:{
kind = 1;
notificationIsPrior = 1;
}
2010-09-15 12:29:18.397 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed
change:{
kind = 1;
new = "lazy value";
}
2010-09-15 12:29:18.400 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed
change:{
kind = 1;
notificationIsPrior = 1;
}
2010-09-15 12:29:18.400 foobar[27795:903] [Foo setBar:] setting value baz
2010-09-15 12:29:18.401 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed
change:{
kind = 1;
new = baz;
}
Si se va a añadir NSKeyValueObservingOptionOld
a la lista de opciones de observación, se cuelga mucho.
Volviendo a un comentario que hice anteriormente; la mejor solución es no hacer la inicialización lenta como parte de su getter/setter. Es muy fino. Es mucho mejor que administres tu estado de gráfico de objetos en un nivel superior y, como parte de eso, tengas una transición de estado que es básicamente del "Yo! Voy a usar este subsistema ahora. ¡Calienta a ese chico malo! " eso hace la inicialización perezosa.
Esta es la respuesta correcta en mi opinión. –
En realidad, no hay ningún cambio que observar al inicializar el objeto de forma perezosa, por lo que esta respuesta es ** no ** correcta. – Sven
¿Eh? Ya sea que se inicializa de forma perezosa o no es irrelevante. Si configuro una observación de KVO de 'theObject' y pongo' self.theObject = ... 'en el getter, entonces esa observación de KV ** disparará **. "Inicialización lenta" es solo un nombre para un patrón; ni el compilador ni el tiempo de ejecución saben nada al respecto. – bbum