关于cocoa:为什么我不应该在init / dealloc中使用Objective C 2.0访问器?

Why shouldn't I use Objective C 2.0 accessors in init/dealloc?

在@mmalc对这个问题的回答中,他指出"一般来说,您不应该在dealloc(或init)中使用accessor方法。"mmalc为什么这么说?

我能想到的唯一真正原因是性能和避免@dynamic setter未知的副作用。

讨论?


它基本上是一个最小化潜在错误的指导方针。

在这种情况下,(可能)您的setter/getter可能无意中对对象的状态做出直接或间接的假设。当对象处于设置或销毁过程中时,这些假设可能是一个问题。

例如,在下面的代码中,观察者不知道"example"正在被销毁,可能会假定已经释放的其他属性是有效的。

(您可能会争辩说,您的对象应该在分解之前删除所有观察者,这是一个很好的实践,也是防止意外问题的另一个准则)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@implementation Example

-(void) setFoo:(Foo*)foo
{
   _foo = foo;
  [_observer onPropertyChange:self object:foo];
}

-(void) dealloc
{
   ...
   self.foo = nil;
}

@end


这一切都是关于使用习惯上一致的代码。如果您对所有代码都进行了适当的模式化,那么有一些规则可以保证在init/dealloc中使用访问器是安全的。

最大的问题是(正如mmalc所说)设置属性默认状态的代码不应该通过访问器,因为它会导致各种各样的棘手问题。catch是init不必设置属性的默认状态。出于许多原因,我一直在转向自初始化的访问器,如下面的简单示例:

1
2
3
4
5
6
7
- (NSMutableDictionary *) myMutableDict {
    if (!myMutableDict) {
        myMutableDict = [[NSMutableDictionary alloc] init];
    }

    return myMutableDict;
}

这种类型的属性初始化允许延迟许多实际上不需要的初始化代码。在上述情况下,in it不负责初始化属性状态,并且在init方法中使用访问器是完全安全的(甚至是必要的)。

诚然,这确实对代码施加了额外的限制,例如,具有自定义访问器的子类对于超类中的属性必须调用超类访问器,但这些限制与cocoa中常见的各种其他限制并不冲突。


你回答了自己的问题:

  • 性能本身可能是一个非常充分的原因(尤其是如果访问器是原子的)。
  • 您应该避免访问器可能产生的任何副作用。
  • 如果类可能是子类的话,后者尤其是一个问题。

    但是,还不清楚为什么要在Objective-C2访问器中专门解决这个问题?无论您自己使用声明的属性还是写访问器,同样的原则都适用。


    可能是setter具有应该运行的逻辑,或者可能是实现使用了与getter/setter不同的名称的ivar,或者可能是需要释放和/或将其值设置为nil的两个ivar。唯一可靠的方法是调用setter。setter的职责是以这样的方式编写:在in it或dealloc期间调用时,不会出现不良的副作用。

    从"可可图案",巴克,雅克特曼,第115页:"…当您将合成实例变量与现代的Objective-C运行时一起使用时,没有实际的替代方法来使用访问器,或者……


    您可以通过在分配/解除分配时不调用setter来创建相同的问题。

    我认为您不能通过直接在in i t/dealloc中使用retain/release来实现任何目的。您只需更改一组可能的错误。

    每次你都要考虑财产分配/解除分配的顺序。


    事实上,对于一个经常来来去去的类(像一个细节视图控制器),您希望在init中使用访问器;否则,您可能最终在viewdidUnload中释放一个您稍后尝试访问的值(它们在cs193p中显示…)