为什么在iOS中使用前导下划线重新命名合成的属性?
可能重复:
如何在cocoaObjective-C类中的variables前面的下划线工作?
在Xcode 4中创build新项目时,样板代码在实现文件中将ivars综合为以下内容时会添加一个下划线字符:
@synthesize window = _window;
要么:
@synthesize managedObjectContext = __managedObjectContext;
有人能告诉我在这里做了什么? 我不是一个完整的nube,但这是我不明白的目标-C的一个方面。
另一个混乱点; 在应用程序委托实现中,在合成如上所述的窗口iVar之后,在应用程序didFinishLaunchingWithOptions:方法中,窗口和viewController ivars使用self:
self.window.rootViewController = self.viewController [self.window makeKeyAndVisible];
但在dealloc方法是_window或_viewController
谢谢
这是以前版本的Objective-C运行时的工件。
最初,@ @synthesize
被用来创build访问器方法,但是运行时仍然需要显式地实例化实例variables:
@interface Foo : Bar { Baz *_qux; } @property (retain) Baz *qux; @end @implementation Foo @synthesize qux = _qux; - (void)dealloc { [_qux release]; [super dealloc]; } @end
人们会在他们的实例variables前加上区分他们的属性(即使苹果公司不希望你使用下划线,但这是另外一回事)。 您将该属性综合为指向该实例variables。 但重点是, _qux
是一个实例variables, self.qux
(或[self qux]
)是发送给对象self
的消息qux
。
我们直接在-dealloc
使用实例variables; 使用访问器方法,而不是看起来像这样(虽然我不build议,因为我会很快解释):
- (void)dealloc { self.qux = nil; // [self setQux:nil]; [super dealloc]; }
这具有释放qux
的效果,以及清零参考的function。 但是这可能会有不幸的副作用:
- 你可能最终会发射一些意外的通知。 其他对象可能正在观察对
qux
更改,这些更改会在使用访问器方法来更改时进行logging。 - (不是每个人都同意这一点:)清零指针作为访问者可能会隐藏您的程序中的逻辑错误。 如果你在对象被释放后访问一个对象的实例variables,那么你正在做一些严重错误的事情。 但是,由于Objective-C的
nil
-messaging语义,你永远不会知道,使用访问器设置为nil
。 如果你直接释放了实例variables,而不是将引用清零,那么访问释放的对象会导致一个巨大的EXC_BAD_ACCESS
。
运行时的更新版本增加了除访问器方法之外的综合实例variables的function。 使用这些版本的运行时,上面的代码可以写成省略实例variables:
@interface Foo : Bar @property (retain) Baz *qux; @end @implementation Foo @synthesize qux = _qux; - (void)dealloc { [_qux release]; [super dealloc]; } @end
这实际上在Foo
上合成了一个名为_qux
的实例variables,可以通过getter和setter消息-qux
和-setQux:
。
我build议不要这样做:有点混乱,但是有一个很好的理由使用下划线; 即防止意外直接接触伊娃。 如果你认为你可以相信自己要记住你使用的是原始实例variables还是访问方法,只需要这样做:
@interface Foo : Bar @property (retain) Baz *qux; @end @implementation Foo @synthesize qux; - (void)dealloc { [qux release]; [super dealloc]; } @end
然后,当你想直接访问实例variables时,只需说qux
(在C语法中用于从一个指针访问一个成员就转换为self->qux
)。 当你想要使用访问器方法(它会通知观察者,做其他有趣的事情,并使内存pipe理更安全,更容易),使用self.qux
( [self qux]
)和self.qux = blah;
( [self setQux:blah]
)。
可悲的是,苹果的示例代码和模板代码很糟糕。 切勿将其用作正确的Objective-C风格的指南,当然不要将其用作正确的软件体系结构的指南。 🙂
这是另一个原因。 如果不强调实例variables,您经常会获得带有参数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
您可以通过强调实例variables来避免警告:
@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
在应用程序didFinishLaunchingWithOptions:方法的窗口和viewController ivars被称为使用自我
不,他们不是。 那些是对属性 window
和viewController
。 这是下划线的要点,使用该属性时(无下划线)以及当直接访问ivar(带下划线)时更清晰。
是的,它只是为了区分对象的引用。 也就是说,如果直接引用对象,则使用下划线,否则使用self来引用对象。