在应用程序 did FinishLaunchingWithOptions: 方法中,使用 self 引用窗口和 viewController 变量

不,他们不是。这些是对 物业 windowviewController的引用。这就是下划线的意义所在,它使得在使用属性(没有下划线)和直接访问 ivar (使用下划线)时更加清晰。

这是 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

人们会给他们的实例变量加上前缀来区分他们的属性(即使苹果不希望你使用下划线,但那是另一回事)。你合成属性指向实例变量。但重点是,_qux是一个实例变量,而 self.qux(或者 [self qux])是发送给对象 self的信息 qux

我们在 -dealloc中直接使用实例变量,而使用访问器方法看起来应该是这样的(虽然我不推荐这样做,原因稍后解释) :

- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}

这会释放 qux,同时也会使参考文献归零,但这可能会产生不幸的副作用:

  • 您最终可能会触发一些意外的通知。其他对象可能观察到对 qux的更改,这些更改在使用访问器方法更改 qux时被记录下来。
  • (并非所有人都同意这一点:)像访问器那样清零指针可能会隐藏程序中的逻辑错误。如果你正在访问一个对象的实例变量,那么这个对象已经被释放了,你正在做一些严重错误的事情。但是,由于 Objective-C 的 nil消息传递语义,您将永远不会知道,因为您已经使用访问器将其设置为 nil。如果你直接释放实例变量而没有清零引用,访问被释放的对象将会引起一个响亮的 ABc2。

运行库的后续版本增加了除访问器方法外合成实例变量的能力。使用这些版本的运行时,上面的代码可以省略实例变量:

@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])。

可悲的是,苹果的样本代码和模板代码糟透了。永远不要将它用作正确 Objective-C 风格的指南,当然也永远不要将它用作正确软件架构的指南。:)

是的,它只是用来区分对象的指称。也就是说,如果直接引用对象,则使用带下划线的方式,否则使用 self 来引用对象。

下面是另一个原因: 不强调实例变量,你经常会得到参数 self.title = titleself.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