可能重复:
How does an underscore in front of a variable in a cocoa objective-c class work?
在Xcode4中创建新项目时,样板代码在合成实现文件中的ivars时会添加一个下划线字符,如下所示:
@synthesize window = _window;
或者:
@synthesize managedObjectContext = __managedObjectContext;
有人能告诉我这里正在完成什么吗?我不是一个十全十美的人,但这是objective-C的一个方面,我不明白。
另一个令人困惑的地方;在应用程序委托实现中,在像上面那样合成窗口iVar之后,在应用程序didFinishLaunchingWithOptions: method中,使用self引用窗口和viewController iVar:
self.window.rootViewController = self.viewController
[self.window makeKeyAndVisible];
但在dealloc方法中,它是_window或_viewController
谢谢
发布于 2011-03-29 08:29:34
这是以前版本的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
发送给object self
的消息。
我们直接在-dealloc
中使用实例变量;改用访问器方法将如下所示(尽管我不推荐这样做,原因我稍后会解释):
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
这具有释放qux
的效果,以及将引用置零的效果。但这可能会有不幸的副作用:
qux
的更改,这些更改是在使用访问器方法更改它时记录的。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风格的指南,当然也不要把它作为正确的软件架构的指南。:)
发布于 2012-05-07 23:17:59
这是另一个原因。如果不对实例变量加下划线,则经常会收到有关参数self.title = title
和self.rating = rating
的警告
@implementation ScaryBugData
@synthesize title;
@synthesize rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // Warning. Local declaration hides instance variable
self.rating = rating; // Warning. Local declaration hides instance variable
}
return self;
}
@end
您可以通过在实例变量下划线来避免警告:
@implementation ScaryBugData
@synthesize title = _title;
@synthesize rating = _rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // No warning
self.rating = rating; // No warning
}
return self;
}
@end
发布于 2011-03-29 08:25:07
应用程序didFinishLaunchingWithOptions中的
:方法使用自身引用窗口和viewController ivars
不,他们不是。这些是对属性window
和viewController
的引用。这就是下划线的意义所在,当属性正在被使用时(没有下划线),以及当ivar被直接访问时(带下划线),它变得更加清晰。
https://stackoverflow.com/questions/5466496
复制相似问题