Pourquoi une propriété en lecture seule permet encore d'écrire avec KVC
-
19-09-2019 - |
Question
Je travaille par la « valeur clé de codage » chapitre « Programmation pour Mac OS X ». Je l'ai construit une interface avec un curseur et une étiquette, à la fois lié à fido, un int. Si je mets la propriété pour fido à lecture seule, déplacer le curseur provoque toujours l'étiquette pour changer sa valeur. Je l'avais supposé que j'obtenir une sorte d'erreur pour cela. Si la propriété est en lecture seule, comment se fait le curseur peut encore écrire à la propriété? Je pensais qu'il aurait pas créé setters et KVC ne fonctionnerait pas. Merci.
Voici le code que je utilise:
#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 texte http://idisk.me.com/nevan/Public /Pictures/Skitch/Window-20091001-174352.png
La solution
AppController.h:
@interface AppController : NSObject
{
int fido;
}
@property (readonly, assign) int fido;
@end
import "AppController.h"
@implementation AppController
@synthesize fido;
...
@end
À ce stade, vous avez déclaré que AppController a une méthode -fido
et vous avez synthétisé cette méthode. Il n'y a pas de méthode de -setFido:
. Alors, pourquoi le « travail » qui suit?
- (id)init
{
if (self=[super init]) {
[self setValue:[NSNumber numberWithInt:5] forKey:@"fido"];
NSNumber *n = [self valueForKey:@"fido"];
NSLog(@"fido = %@", n);
}
return self;
}
(BTW: je fixe votre -init pour mettre en œuvre le modèle correct)
Cela fonctionne parce que KVC suit une heuristique pour définir ou obtenir la valeur. L'appel à -setValue:forKey:
recherche d'abord -setFoo:
. Si non trouvé, il recherche alors l'instance foo
variable et fixe directement.
Notez que si vous changez l'instance fido
variable _fido
, l'ensemble fonctionnera, mais le valueForKey
retourne 0 car il appelle la méthode de synthèse (depuis que je suis sur 64 bits, la @synthesize synthétise une variable d'instance de fido
. Confondre, je sais.).
Si vous deviez changer le nom de votre Ivar à bar
puis utilisez @synthesize foo=bar;
, le code échoue lors de l'exécution.
Vous allez voir:
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
Autres conseils
Avoir la propriété readonly signifie que le compilateur ne vous générer setter pour cette propriété. Il est toujours légal d'écrire via KVO / KVC.
Les directives du compilateur @property
et @synthesize
sont des moyens juste sténographie pour créer les méthodes pour obtenir et définir la variable en question.
La méthode setter créé est nommé setFido:
, et la méthode de lecture est vient d'être nommée fido
.
Lorsque vous spécifiez lecture seule, je crois que le compilateur dit simplement de ne pas créer la méthode setter, mais seulement le getter. Il ne met pas toute sorte de barrière de la manière de définir la variable par d'autres moyens.
(espoir que j'ai tout ce droit. Bonne chance!)