Possible Duplicate:
How does an underscore in front of a variable in a cocoa objective-c class work?
在 Xcode 4 中创建新项目时,样板代码在合成实现文件中的 ivars 时添加下划线字符为:
@synthesize window = _window;
或:
@synthesize managedObjectContext = __managedObjectContext;
谁能告诉我这里正在完成什么?我不是一个完整的 nube,但这是我不理解的 Objective-C 的一个方面。
另一个混淆点;在app delegate实现中,如上合成window iVar后,在应用didFinishLaunchingWithOptions:方法中,window和viewController ivars使用self来引用:
self.window.rootViewController = self.viewController
[self.window makeKeyAndVisible];
但在 dealloc 方法中它是 _window 或 _viewController
谢谢
最佳答案
这是以前版本的 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]
)是消息 qux
发送到对象 self
。
我们在-dealloc
中直接使用实例变量;使用访问器方法看起来像这样(虽然我不推荐它,原因我稍后会解释):
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
这具有释放 qux
的效果,以及将引用归零。但这可能会产生不幸的副作用:
- 您最终可能会触发一些意外通知。其他对象可能正在观察对
qux
的更改,这些更改会在使用访问器方法对其进行更改时记录下来。 - (不是每个人都同意这一点:)像访问器那样将指针清零可能会隐藏程序中的逻辑错误。如果您在对象被释放后访问对象的实例变量,那么您做的事情是严重错误的。然而,由于 Objective-C 的
nil
消息语义,你永远不会知道,使用访问器设置为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 风格的指南,当然也永远不要将其用作正确的软件架构的指南。 :)
关于objective-c - 为什么在 iOS 中使用前导下划线重命名合成属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5466496/