为什么readonly属性仍允许使用KVC进行写入

nev*_*ing 5 getter setter properties objective-c

我正在研究"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
Run Code Online (Sandbox Code Playgroud)

替代文字http://idisk.me.com/nevan/Public/Pictures/Skitch/Window-20091001-174352.png

bbu*_*bum 16

AppController.h:

@interface AppController : NSObject
{
        int fido;
}

@property (readonly, assign) int fido;
@end
Run Code Online (Sandbox Code Playgroud)

导入"AppController.h"

@implementation AppController
@synthesize fido;
...
@end
Run Code Online (Sandbox Code Playgroud)

此时,您已声明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;
}
Run Code Online (Sandbox Code Playgroud)

(顺便说一句:我修复了你的-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
Run Code Online (Sandbox Code Playgroud)

  • 你也可以使用+(BOOL)accessInstanceVariablesDirectly {return NO; 消除这种KVC行为 (9认同)