Why does a readonly property still allow writing with KVC
getter, objective-c, properties, setter
Solution
AppController.h:
@interface AppController : NSObject
{
int fido;
}
@property (readonly, assign) int fido;
@end
import "AppController.h"
@implementation AppController
@synthesize fido;
...
@end
At this point, you have declared that AppController has a `-fido` method and you have synthesized that method. There is no `-setFido:` method. So, why does the following "work"?
- (id)init
{
if (self=[super init]) {
[self setValue:[NSNumber numberWithInt:5] forKey:@"fido"];
NSNumber *n = [self valueForKey:@"fido"];
NSLog(@"fido = %@", n);
}
return self;
}
(BTW: I fixed your -init to implement the correct pattern)
This works because KVC follows a heuristic to set or get the value. The call to `-setValue:forKey:` first looks for `-setFoo:`. If not found, it then looks for the instance variable `foo` and sets it directly.
Note that if you change the instance variable `fido` to `_fido`, the set will work, but the `valueForKey` will return 0 as it calls the synthesized method (since I'm on 64 bit, the @synthesize synthesizes a `fido` instance variable. Confusing, I know.).
If you were to change the name of your ivar to `bar` and then use `@synthesize foo=bar;`, the code would fail at runtime.
You'll see:
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
Problem
I'm working through the "Key Value Coding" chapter in "Programming for Mac OS X". I've built an interface with a slider and a label, both bound to fido, an int. If I set the property for fido to readonly, moving the slider still causes the label to change it's value. I had assumed that I'd get some sort of error for this. If the property is readonly, how come the slider can still write to the property? I thought that it would have no setters created, and KVC wouldn't work. Thanks. Here's the code I'm using: ``` #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