我正在完成“Mac OS X编程”中的“键值编码”一章。我已经构建了一个带滑块和标签的界面,两者都绑定到fido,一个int。如果我将fido的属性设置为readonly,则移动滑块仍会导致标签更改其值。我以为我会因此而遇到某种错误。如果属性是readonly,滑块如何仍然可以写入属性?我认为它没有创建setter,KVC也行不通。感谢。
这是我正在使用的代码:
#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
答案 0 :(得分:16)
AppController.h:
@interface AppController : NSObject
{
int fido;
}
@property (readonly, assign) int fido;
@end
@implementation AppController
@synthesize fido;
...
@end
此时,您已声明AppController具有-fido
方法,并且您已合成该方法。没有-setFido:
方法。那么,为什么以下“工作”?
- (id)init
{
if (self=[super init]) {
[self setValue:[NSNumber numberWithInt:5] forKey:@"fido"];
NSNumber *n = [self valueForKey:@"fido"];
NSLog(@"fido = %@", n);
}
return self;
}
(顺便说一句:我修了你的-init来实现正确的模式)
这是有效的,因为KVC遵循启发式来设置或获取值。对-setValue:forKey:
的调用首先查找-setFoo:
。如果未找到,则会查找实例变量foo
并直接设置它。
请注意,如果您将实例变量fido
更改为_fido
,该集合将起作用,但valueForKey
将在调用合成方法时返回0(因为我在64位,@synthesize合成一个fido
实例变量。我知道这很混乱。)。
如果您要将ivar的名称更改为bar
,然后使用@synthesize foo=bar;
,则代码将在运行时失败。
你会看到:
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
答案 1 :(得分:1)
拥有readonly属性意味着编译器不会为该属性生成setter。通过KVO / KVC写入它仍然是合法的。
答案 2 :(得分:1)
编译器指令@property
和@synthesize
只是创建获取和设置相关变量的方法的简便方法。
创建的setter方法名为setFido:
,getter方法名为fido
。
当你指定readonly时,我相信只是告诉编译器不要创建setter方法,而只是创建getter。它没有通过其他方式设置变量的任何障碍。
(希望我已经做对了。祝你好运!)