¿Por qué una propiedad de sólo lectura todavía permiten escribir con KVC
-
19-09-2019 - |
Pregunta
Estoy trabajando a través del capítulo "Valor de clave de codificación" en "Programación para Mac OS X". He construido una interfaz con un control deslizante y una etiqueta, tanto ligada a Fido, un int. Si establece la propiedad de sólo lectura a Fido, moviendo el deslizador sigue causando la etiqueta para cambiar su valor. Había supuesto que me gustaría conseguir algún tipo de error para esto. Si la propiedad es de sólo lectura, ¿cómo es que el cursor puede escribir todavía a la propiedad? Pensé que no tendría ningún set creados, y KVC no funcionaría. Gracias.
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
Solución
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 existe un método -setFido:
. Así que, ¿por qué hace lo 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 un heurística para establecer u obtener el valor. La llamada a -setValue:forKey:
primero busca -setFoo:
. Si no lo encuentra, a continuación, busca la instancia foo
variable y fija 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 se va a cambiar el nombre de su Ivar a bar
y luego usar @synthesize foo=bar;
, el código podría fallar en tiempo de ejecución.
Usted verá:
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
Otros consejos
Tener la propiedad de sólo lectura significa que el compilador no generará que setter para esa propiedad. Es todavía legal para escribir en él a través de MVA / KVC.
El @property
directivas del compilador y @synthesize
son simplemente formas de taquigrafía para crear los métodos para obtener y establecer la variable en cuestión.
El método setter creado se denomina setFido:
, y el método getter se acaba de nombrar fido
.
Cuando se especifica sólo lectura, creo que simplemente le dice al compilador que no crear el método de selección, pero sólo el captador. Que no pone ningún tipo de barrera en la forma de establecer la variable por otros medios.
(Esperanza Tengo todo ese derecho. Buena suerte!)