从 C++ 到 Objective-C(22):隐式代码(续二)

属性的自定义实现

上一章中我们提到的代码中有两个关键字@synthesize@dynamic@dynamic意思是由开发人员提供相应的代码:对于只读属性需要提供 setter,对于读写属性需要提供 setter 和 getter。@synthesize意思是,除非开发人员已经做了,否则由编译器生成相应的代码,以满足属性声明。对于上次的例子,如果开发人员提供了-(NSString*)registration,编译器就会选择这个实现,不会用新的覆盖。因此,我们可以让编译器帮我们生成代码,以简化我们自己的代码输入量。最后,如果编译期没有找到访问器,而且没有使用@synthesize声明,那么它就会在运行时添加进来。这同样可以实现属性的访问,但是即使这样,访问器的名字也需要在编译期决定。如果运行期没有找到访问器,就会触发一个异常,但程序不会停止,正如同方法的缺失。当我们使用@synthesize时,编译器会被要求绑定某一特定的数据成员,并不一定是一样的名字。

@interface A : NSObject {
    int _foo;
}
@property int foo;
@end

@implementation A
@synthesize foo=_foo; // 绑定 "_foo" 而不是 "foo"
@end

访问属性的语法

为获取或设置属性,我们使用点号:这同简单的 C 结构是一致的,也是在 keypath 中使用的语法,其性能与普通方法调用没有区别。

@interface A : NSObject {
    int i;
}
@property int i;
@end

@interface B : NSObject {
    A* myA;
}
@property(retain) A* a;
@end
...
A* a = ...
B* b = ...;
a.i = 1; // 等价于 [a setI:1];
b.myA.i = 1;// 等价于 [[b myA] setI:1];

请注意上面例子中 A 类的使用。self->iself.i是有很大区别的:self->i直接访问数据成员,而self.i则是使用属性机制,是一个方法调用。

高级细节

64 位编译器上,Objective-C 运行时环境与 32 位有一些不同。关联到@property的实例数据可能被忽略掉,例如被视为隐式的。更多细节请阅读 Apple 的文档。

One Response

  1. willonboy's blog 2011年4月9日

Leave a Reply