为什么只读属性仍然允许使用 KVC 写入
我正在学习“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
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
AppController.h:
import "AppController.h"
此时,您已经声明 AppController 有一个
-fido
方法,并且您已经合成了该方法。没有-setFido:
方法。那么,为什么下面的“有效”呢?(顺便说一句:我修复了你的 -init 以实现正确的模式)
这是有效的,因为 KVC 遵循启发式来设置或获取值。对
-setValue:forKey:
的调用首先查找-setFoo:
。如果没有找到,它就会查找实例变量foo
并直接设置它。请注意,如果将实例变量
fido
更改为_fido
,该集合将起作用,但valueForKey
在调用合成方法时将返回 0 (因为我使用的是 64 位,所以 @synthesize 合成了一个fido
实例变量。我知道这很令人困惑。)。如果您将 ivar 的名称更改为
bar
,然后使用@synthesize foo=bar;
,代码将在运行时失败。你会看到:
AppController.h:
import "AppController.h"
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"?(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 variablefoo
and sets it directly.Note that if you change the instance variable
fido
to_fido
, the set will work, but thevalueForKey
will return 0 as it calls the synthesized method (since I'm on 64 bit, the @synthesize synthesizes afido
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:
具有只读属性意味着编译器不会为该属性生成设置器。通过 KVO/KVC 写入它仍然是合法的。
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.
编译器指令
@property
和@synthesize
只是创建获取和设置相关变量的方法的简写方式。创建的 setter 方法名为
setFido:
,getter 方法名为fido
。当您指定 readonly 时,我相信只是告诉编译器不要创建 setter 方法,而只创建 getter 方法。它不会对通过其他方式设置变量的方式设置任何障碍。
(希望我做对了。祝你好运!)
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 namedfido
.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!)