为什么不应该在init方法中使用访问器方法?

7
从苹果的有关内存管理文档中可以得知:
唯一不应该在init方法和dealloc方法中使用访问器方法来设置实例变量的地方。为了使用表示零的数字对象初始化计数器对象,您可以按照以下方式实现一个init方法:
为了允许使用计数器以非零计数进行初始化,您可以按照以下方式实现一个initWithCount:方法:
- initWithCount:(NSNumber *)startingCount {
    self = [super init];
    if (self) {
        count = [startingCount copy];
    }
    return self;
}

为什么不呢?

你能添加一个指向你的文档来源的链接吗? - Scott M.
@Scott:我刚刚在问题本身中添加了一个链接。 - Pierre Valade
即使我找不到明确简单的答案,我猜Perspx是正确的,这是一个与此问题重复的问题。 - Pierre Valade
可能是[Objective-C点语法和初始化]的重复问题。(https://dev59.com/O07Sa4cB1Zd3GeqP6cVZ) - JeremyP
建造和拆除房屋与居住其中并不相同:https://dev59.com/f0_Ta4cB1Zd3GeqPBogo#3408931 问候 - user413473
4个回答

16

请看我对这个问题的回答。

主要原因是子类可能会重写你的访问器并执行不同的操作。子类的访问器可能会假设完全初始化的对象,即子类的init方法中的所有代码都已运行。实际上,在你的init方法运行时,它们都尚未运行。同样,子类的访问器可能依赖于子类的dealloc方法尚未运行,但当你的dealloc方法正在运行时,这显然是错误的。

为了扩展您的示例,如果您改为执行以下操作:

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

但是如果一个子类重写了 setCount 方法,而不是设置您的计数变量,您可能会遇到麻烦。


2

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

然而,在某些情况下,您必须在初始化程序中使用setter。这是当实例变量在超类中声明时;无论如何,您都不能直接访问实例变量,因此必须使用setter。

另一种情况是属性使用延迟初始化。在这种情况下,您必须通过getter进行访问;如果不这样做,实例变量将永远没有机会被初始化。例如,EOCPerson类可能具有一个属性,以便访问表示每个人大脑的复杂对象。如果这个属性很少被访问并且设置起来很昂贵,您可以在getter中懒惰地初始化它,像这样:

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

如果您直接访问实例变量并且 getter 尚未调用,那么大脑就不会被设置,并且您必须为所有访问大脑属性的操作调用访问器。

-- 马特·加洛维的 EOC 书籍第7项


1
从面向对象的角度来看(因为我对objective-c没有经验),你不会使用正在构造的对象的方法。这在某些语言中是可能的,但你已经可以访问私有变量。对象的构建尚未完成,因此它还没有准备好进行操作。一旦对象构建完成,它就处于一个已知的良好状态(或者至少被认为是如此),并且可以执行相关操作。

是的,我明白如果重新定义init方法可能会出现自递归的问题。 但是,从技术角度来看,如果定义另一个方法,比如initWithCount,我不明白其中的意义。 - Pierre Valade
类、实例和静态方法是在创建类对象时创建的静态对象。严格来说,在任何面向对象编程语言中,构造函数都不会创建实例 - 它们只是受语法保护的实例方法,需要绑定到在调用时创建并提供给构造函数的实例,也就是说,在已经拥有一个实例可以使用的情况下,没有任何这样的面向对象编程语言会禁止您在构造函数中访问实例方法。 - Filip Dupanović

-3
在现代的 Objective-C 中,你应该能够在 init 方法中使用访问器方法。编译器错误很少情况下几乎不会发生。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接