2009-10-01 10 views
5

? Estoy trabajando en el capítulo "Codificación de valor de clave" en "Programación para Mac OS X". Construí una interfaz con un control deslizante y una etiqueta, ambos vinculados a fido, un int. Si configuro la propiedad de fido como de solo lectura, mover el control deslizante aún hace que la etiqueta cambie su valor. Supuse que obtendría algún tipo de error por esto. Si la propiedad es de solo lectura, ¿cómo es que el control deslizante todavía puede escribir en la propiedad? Pensé que no tendría setters creados, y KVC no funcionaría. Gracias.¿Por qué una propiedad de solo lectura todavía permite escribir con KVC

Aquí está el código que estoy usando:

#import <Cocoa/Cocoa.h> 

@interface AppController : NSObject 
{ 
    int fido; 
} 

@property (readonly, assign) int fido; 

@end 

#import "AppController.h" 

@implementation AppController 

@synthesize fido; 

- (id)init 
{ 
    [super init]; 
    [self setValue:[NSNumber numberWithInt:5] forKey:@"fido"]; 
    NSNumber *n = [self valueForKey:@"fido"]; 
    NSLog(@"fido = %@", n); 
    return self; 
} 
@end 

alt text http://idisk.me.com/nevan/Public/Pictures/Skitch/Window-20091001-174352.png

Respuesta

16

AppController.h:

@interface AppController : NSObject 
{ 
     int fido; 
} 

@property (readonly, assign) int fido; 
@end 

importación "AppController.h"

@implementation AppController 
@synthesize fido; 
... 
@end 

En este punto, usted ha declarado que AppController tiene un método -fido y ha sintetizado ese método. No hay un método -setFido:. Entonces, ¿por qué el siguiente "trabajo"?

- (id)init 
{ 
     if (self=[super init]) { 
      [self setValue:[NSNumber numberWithInt:5] forKey:@"fido"]; 
      NSNumber *n = [self valueForKey:@"fido"]; 
      NSLog(@"fido = %@", n); 
     } 
     return self; 
} 

(Por cierto: me fijo su -init para implementar el patrón correcto)

Esto funciona porque KVC sigue una heurística a establecer u obtener el valor. La llamada al -setValue:forKey: primero busca -setFoo:. Si no se encuentra, busca la variable de instancia foo y la establece directamente.

Tenga en cuenta que si cambia la variable de instancia fido a _fido, el conjunto va a funcionar, pero el valueForKey devolverá 0, ya que llama al método sintetizado (ya que estoy en 64 bits, el @synthesize sintetiza una variable de instancia fido . Confuso, lo sé.).

Si cambiaras el nombre de tu ivar por bar y luego usaras @synthesize foo=bar;, el código fallaría en tiempo de ejecución.

Verás:

2009-10-01 08:59:58.081 dfkjdfkjfjkfd[24099:903] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<AppController 0x20000e700> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key fido.' 
*** Call stack at first throw: 
(
    0 CoreFoundation      0x00007fff85b055a4 __exceptionPreprocess + 180 
    1 libobjc.A.dylib      0x00007fff85c5a0f3 objc_exception_throw + 45 
    2 CoreFoundation      0x00007fff85b5caf9 -[NSException raise] + 9 
    3 Foundation       0x00007fff814e14f5 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 434 
(
    0 CoreFoundation      0x00007fff85b055a4 __exceptionPreprocess + 180 
    1 libobjc.A.dylib      0x00007fff85c5a0f3 objc_exception_throw + 45 
    2 CoreFoundation      0x00007fff85b5caf9 -[NSException raise] + 9 
    3 Foundation       0x00007fff814e14f5 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 434 
    4 dfkjdfkjfjkfd      0x0000000100000d96 -[AppController init] + 130 
+9

También puede usar + (BOOL) accessInstanceVariablesDirectly {return NO; } para eliminar este comportamiento KVC – sbooth

+0

Buen punto y un buen hábito para entrar. ¡Gracias! – bbum

+0

Excelente respuesta, gracias. La razón por la que formulé esta pregunta fue que uno de los puntos principales del capítulo es que KVC usa los setters y getters. Supuse que esa era la única forma en que trabajaban. El estilo init es el estilo que usa en el libro. Él dice que las clases que subclases nunca devuelven nada, por lo que deja fuera el cheque por simplicidad. –

1

Tener sólo lectura propiedad significa que el compilador no generará que setter para esa propiedad. Todavía es legal escribir a través de KVO/KVC.

+1

eso no es lo que está pasando aquí. – bbum

1

Las directivas de compilación @property y @synthesize son solo formas abreviadas de crear los métodos para obtener y establecer la variable en cuestión.

El método setter creado se llama setFido:, y el método getter se acaba de llamar fido.

Cuando especifiques de solo lectura, creo que simplemente le dice al compilador que no cree el método setter, sino solo el getter. No pone ningún tipo de barrera en el camino de establecer la variable por otros medios.

(Hope lo que tengo Todo ese derecho Buena suerte.!)

+0

Más o menos correcto.Ver mi respuesta para detalles. – bbum

Cuestiones relacionadas