5

我正在阅读“Mac OS X 编程”中的“键值编码”一章。我已经建立了一个带有滑块和标签的界面,两者都绑定到 fido,一个 int。如果我将 fido 的属性设置为只读,移动滑块仍会导致标签更改其值。我曾假设我会为此遇到某种错误。如果属性是只读的,为什么滑块仍然可以写入属性?我认为它不会创建任何设置器,并且 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

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

4

3 回答 3

16

应用控制器.h:

@interface AppController : NSObject
{
        int fido;
}

@property (readonly, assign) int fido;
@end

导入“AppController.h”

@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 遵循启发式方法来设置或获取值。对 first 的调用-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
于 2009-10-01T16:00:38.610 回答
1

拥有 readonly 属性意味着编译器不会为您生成该属性的 setter。通过 KVO/KVC 写入它仍然是合法的。

于 2009-10-01T08:50:34.903 回答
1

编译器指令只是创建获取和设置相关变量的方法的简写方式@property@synthesize

创建的 setter 方法是命名setFido:的,而 getter 方法只是命名的fido

当您指定只读时,我相信这只是告诉编译器不要创建 setter 方法,而只创建 getter。它不会对通过其他方式设置变量的方式设置任何障碍。

(希望我做对了。祝你好运!)

于 2009-10-01T15:34:44.387 回答