Having readonly property means that compiler won't generate you setter for that property. It's still legal to write to it via KVO/KVC.
The compiler directives @property and @synthesize are just shorthand ways to create the methods to get and set the variable in question.
The setter method created is named 'setFido', and the getter method is just named 'fido'.
When you specify readonly, I believe that simply tells the compiler not to create the setter method, but only the getter. It doesn't put any sort of barrier in the way of setting the variable by other means.
(Hope I've got all that right. Good luck!)
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