这个问题已经在这里有了答案:




已关闭8年。






在Xcode 4中创建新项目时,样板代码在将实现文件中的ivars合成为以下内容时会添加下划线字符:

@synthesize window = _window;

或者:
@synthesize managedObjectContext = __managedObjectContext;

有人可以告诉我这里正在完成什么吗?我不是一个完整的小伙子,但这是我不了解的Objective-C的一个方面。

另一个困惑点;在应用程序委托(delegate)实现中,按照上述方法合成窗口iVar之后,在应用程序didFinishLaunchingWithOptions:方法中,使用self来引用window和viewController ivars:
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中使用实例变量;相反,使用accessor方法看起来像这样(尽管我不建议这样做,出于稍后将解释的原因):
- (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风格的指南,当然也绝不要将其用作适当的软件体系结构的指南。 :)

    10-08 05:45