在init和dealloc方法中有效使用访问器?

Dav*_*ong 24 initialization properties objective-c accessor dealloc

我现在从几个来源(stackoverflow.com,cocoa-dev,文档,博客等)中听到,在init和dealloc方法中使用访问器和设置(foo,setFoo :)是"错误的".据我所知,如果你这样做,很可能会混淆其他正在观察财产的物体.(这里给出一个简单的例子)

但是,由于以下原因,我不得不说我不同意这种做法:

新的Objective-C运行时(iPhone上的那个和10.5中的64位运行时)允许您在声明相应的ivar的情况下声明属性.例如,以下类将在10.5或iPhone(设备,而不是模拟器)上编译得很好:

@interface Foo : NSObject { }

  @property (retain) id someObject;

@end

@implementation Foo

  @synthesize someObject;

@end
Run Code Online (Sandbox Code Playgroud)

理解上面是一个完全有效的Objective-C类,假设我决定编写一个初始化程序,并且出于内存管理的目的,使用dealloc方法(因为在iPhone上没有GC).我读过有关初始化器和释放器的所有内容都会让我编写以下两种方法:

- (id) init {
  if (self = [super init]) {
    //initialize the value of someObject to nil
    [self setSomeObject:nil];
  }
  return self;
}

- (void) dealloc {
  //setting someObject to nil will release the previous value
  [self setSomeObject:nil];
  [super dealloc];
}
Run Code Online (Sandbox Code Playgroud)

但是,根据文件和流行的观点,这是"错误的".所以我的问题是这样的:

  1. 如何在不使用访问器的情况下初始化someObject?您可能会说编译器(或运行时或其他)将确保someObject已设置为nil,但我相信依赖它会是不正确的行为.在C语言中有一个不错的背景,由于没有正确初始化变量,我看到了相当数量的错误,这似乎没有什么不同.
  2. 如果我不应该在dealloc方法中使用访问器,我该如何释放someObject?

如果其中任何一个的答案是"你不能",那么在init和dealloc方法中使用访问器怎么可能不好?

Rob*_*ier 9

编辑(2013年2月13日):正如我在下面的评论中所指出的那样,特别是在增加ARC之后,我已经改变了主意.在ARC之前,由于不正确的ivar分配,我看到了很多导致崩溃的错误init.IMO,特别是与初级团队合作,使用访问器的罕见问题init被ivar访问的常见错误所抵消.由于ARC已经解决了这些类型的bug,罕见的,但是,可能的错误,在使用访问init可能会导致更重要,所以我切换到支持直接使用实例变量的initdealloc,只有在那些地方; 其他地方的访问器是可能的(显然你不能在访问器本身内部使用访问器....)


PRE-ARC回答

我强烈反对那些反对访问者的人-init.在几乎所有情况下,这都是使用访问器的一个非常好的地方,并且它节省了我在新的Cocoa编码器中看到的许多错误,这些错误在分配时总是无法保留-init.

-dealloc是一个更强硬的电话.我有自然倾向于在那里使用访问器(以便它们在任何地方使用),但它可能会导致由于KVO引起的麻烦(如果你在你的setter中发布更改通知,甚至是NSNotifications).也就是说,虽然我没有使用访问器-dealloc,但我认为这是非常有争议的,Apple对此非常不一致(我们知道他们正在调用setView:UIViewController -dealloc).

在任何情况下,我都会说访问器的使用不足已导致100倍的过度使用错误.我总是错误地使用它们,除非有充分的理由不这样做.

  • 一年后,我的职位变得柔和了.在-init中存在访问者的危险.如果子类重写访问器并且超类的-init调用它,则该对象可能处于不一致状态.问题是,不可能知道你的子类是否会这样做.这是否真的可能取决于您的环境以及是否有不同的组编写超类和子类.制定此规则可以大大减少我们的jr开发人员之间的崩溃,我们从未遇到过上述问题.但是可能存在危险. (6认同)
  • 如果在init中分配了每个需要保留的ivar,则只能获得此平衡.在init之后使ivars保持为零是很常见的(懒惰加载对象尤其如此,并且是非常重要的性能优化).所以我不相信你可以在没有禁止重要实施方法的情况下实际保持这种平衡. (4认同)
  • 我知道这个线程已经空闲了很长一段时间,但值得注意的是,即使属性的内存管理语义发生变化,访问器也可以帮助维护代码的有效性.这主要与`dealloc`有关,其中`self.var = nil;`即使`var`被赋值而不被保留也是有效的,而`[var release];`则不会. (3认同)

BJ *_*mer 8

据我所知,合成的ivars不能直接访问的当前10.5行为被Apple认为是一个bug; 你应该能够直接访问它,但不能.

因此,你应该能够做到:

someObject = nil;
Run Code Online (Sandbox Code Playgroud)

代替

self.someObject = nil;
Run Code Online (Sandbox Code Playgroud)

与此同时,直接使用访问器是唯一的方法,无需提供明确的ivar.

更新:此错误已得到修复; 你现在可以做得someObject = nil很好.

  • 有趣.在Xcode中玩了一下之后,你可以*直接访问合成的ivar.整齐. (3认同)