这是以前版本的 Objective-C 运行时的工件。
最初,@synthesize 用于创建访问器方法,但运行时仍然要求必须显式实例化实例变量:
@interface Foo : Bar {
Baz *_qux;
}
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
人们会为他们的实例变量添加前缀以将它们与他们的属性区分开来(即使 Apple 不希望您使用下划线,但这是另一回事)。您综合该属性以指向实例变量。但重点是,_qux 是一个实例变量,self.qux(或[self qux])是发送给对象self 的消息qux。
我们直接在-dealloc中使用实例变量;使用访问器方法看起来像这样(虽然我不推荐它,原因我稍后会解释):
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
这具有释放qux 的效果,以及将引用归零。但这可能会产生不幸的副作用:
- 您最终可能会触发一些意外通知。其他对象可能正在观察对
qux 的更改,这些更改会在使用访问器方法对其进行更改时记录下来。
- (并非所有人都同意这一点:)像访问器那样将指针清零可能会隐藏程序中的逻辑错误。如果您曾经在对象被释放后访问该对象的实例变量,那么您就做错了。然而,由于 Objective-C 的
nil-messaging 语义,你永远不会知道,使用访问器设置为nil。如果您直接释放实例变量而不将引用归零,那么访问已释放的对象会引起很大的EXC_BAD_ACCESS。
运行时的更高版本除了访问器方法外,还增加了合成实例变量的能力。使用这些版本的运行时,上面的代码可以省略实例变量:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
这实际上在Foo 上合成了一个名为_qux 的实例变量,由getter 和setter 消息-qux 和-setQux: 访问。
我不建议这样做:它有点混乱,但使用下划线有一个很好的理由;即,防止意外直接访问 ivar。如果您认为您可以相信自己记住您使用的是原始实例变量还是访问器方法,请改为这样做:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux;
- (void)dealloc {
[qux release];
[super dealloc];
}
@end
然后,当您想直接访问实例变量时,只需说qux(在 C 语法中转换为self->qux,用于从指针访问成员)。当你想使用访问器方法时(它会通知观察者,做其他有趣的事情,让事情在内存管理方面更安全、更容易),使用self.qux ([self qux]) 和self.qux = blah; ([self setQux:blah]) .
这里可悲的是,Apple 的示例代码和模板代码很烂。永远不要将其用作正确的 Objective-C 风格的指南,当然也永远不要将其用作正确的软件架构的指南。 :)