为什么我不在init方法中使用访问器方法

时间:2010-08-06 13:48:31

标签: objective-c memory-management

关于Memory Management的Apple文档:

  

您不应该使用访问器方法来设置实例变量的唯一地方是init方法和dealloc。要使用表示零的数字对象初始化计数器对象,可以按如下方式实现init方法:

     

要允许使用非零计数初始化计数器,您可以按如下方式实现initWithCount:方法:

- initWithCount:(NSNumber *)startingCount {
    self = [super init];
    if (self) {
        count = [startingCount copy];
    }
    return self;
}

为什么不呢?

4 个答案:

答案 0 :(得分:16)

请参阅我对this question的回答。

  

主要原因是因为子类可能会覆盖您的访问者并执行不同的操作。子类的访问器可能假定一个完全初始化的对象,即子类的init方法中的所有代码都已运行。事实上,当你的init方法运行时,它都没有。类似地,子类的访问器可能依赖于子类的dealloc方法没有运行。当你的dealloc方法运行时,这显然是错误的。

要扩展您的示例,如果您已完成

- initWithCount:(NSNumber *)startingCount {
    self = [super init];
    if (self) {
        [self setCount: [startingCount copy]];
    }
    return self;
}

但是一个子类已经覆盖了setCount:除了设置你的count变量之外还做一些事情,你可能遇到麻烦。

答案 1 :(得分:2)

JeremyP提出了一个很好的观点。由于setter调用的语法总是涉及" self",其类型是在运行时确定的,因此子类实例可以调用其重写的setter版本,如果" self"是真正的子类对象......

但是,在某些情况下,您必须在初始化程序中使用setter。这是在超类中声明实例变量的时候;您无法直接访问实例变量,因此必须使用setter。

另一种情况是属性使用延迟初始化。在这种情况下,你必须通过吸气剂;如果不这样做,实例变量永远不会有机会被初始化。例如,EOCPerson类可能具有一个属性,可以访问代表每个人大脑的复杂对象。如果很少访问此属性并且设置成本很高,您可以在getter中懒惰地初始化它,如下所示:

- (EOCBrain*)brain { if (!_brain) {
        _brain = [Brain new];
    }
return _brain; }

如果你直接访问实例变量并且还没有调用getter,那么就不会设置大脑,你必须调用访问器才能访问大脑属性。

- Matt Galloway的EOC书籍Item7

答案 2 :(得分:1)

从OOP的角度来看(因为我没有使用objective-c的经验),你不会使用当前正在构造的对象的方法。这在某些语言中是可行的,但您已经可以访问私有变量。对象结构尚未完成,因此尚未准备好进行操作。一旦构造了对象,它就处于已知的良好状态(或者假定它是这样)并且它可以执行。

答案 3 :(得分:-3)

在现代目标C中,您应该能够在init中使用访问器方法。如果几乎不发生,编译器故障将很明显