可以做到以下几点吗?
1) 非指定初始化程序调用超类的指定初始化程序
2) 类的指定初始化程序调用超类的非指定初始化程序?
或者流程必须是:
a) 指定初始化器必须调用超类的指定初始化器
b) 非指定初始化器必须调用自己类的指定初始化器
如果违反上述(1)或(2),会发生什么?(或者,如果我们必须始终遵循(a)和(b),那么背后的原因是什么?)
可以做到以下几点吗?
1) 非指定初始化程序调用超类的指定初始化程序
2) 类的指定初始化程序调用超类的非指定初始化程序?
或者流程必须是:
a) 指定初始化器必须调用超类的指定初始化器
b) 非指定初始化器必须调用自己类的指定初始化器
如果违反上述(1)或(2),会发生什么?(或者,如果我们必须始终遵循(a)和(b),那么背后的原因是什么?)
指定初始化器的意义在于它是知道如何正确设置手头对象的初始化器。类中的所有其他初始化程序都应该调用指定的初始化程序;如果他们不这样做,则对象可能无法正确初始化。
Apple 的 Cocoa 文档讨论了如何处理多个初始化器,它包括以下内容:
采用完整的初始化参数的类的初始化器通常是指定的初始化器。子类的指定初始化程序必须通过向 super 发送消息来调用其超类的指定初始化程序。
这有点模棱两可——听起来子类的指定初始化程序必须调用其超类的指定初始化程序。但我认为这不是真正的意图。这里真正的重点是指定的初始化器有责任通过发送消息来确保超类被正确初始化super
。如果您碰巧通过调用super
的非指定初始化程序之一来做到这一点,那么只要该初始化程序最终导致调用指定的初始化程序,那应该没问题。出于这个原因,我不认为(2)是一个问题。
进一步阅读我们有:
便利(或辅助)初始化程序——可以包括 init——不调用 super。
所以他们在这里说的是指定初始化程序和任何其他初始化程序之间的一个重要区别是指定初始化程序是唯一向super
.
回到(1),如果您有一个调用 的“非指定”初始化程序[super init]
,那并不是真正的非指定初始化程序。您的方法通过向 发送初始化消息来承担指定初始化程序的责任super
。这不一定是个问题——请注意 UIView 有两个指定的初始化程序——但它违反了通常的约定,所以你应该有一个很好的理由这样做。
由于创建指定的初始化程序是不正式的,因此是否违反规则取决于您。
具有多个初始化器的类的常见做法是将接受最多参数的类设为指定初始化器,并让所有其他初始化器调用它。只有指定的初始化程序才能调用超类的指定初始化程序,这遵循相同的规则。
如果其他人将您的类子类化并调用指定的初始化程序,则他们确定所有实例变量都已正确初始化。如果您的课程不遵循这些常见做法,您可能会为自己创建一个混乱的课程,但让其他人更难使用它。
可以做到以下几点吗?
1) 非指定初始化器调用超类的指定初始化器
它实际上必须完成,因为作为子类实现者,您无法知道超类指定初始化程序中的代码并自己实现它而无需占用代码。你没有其他合理的方法来初始化超类。
无论您是子类还是外部客户端,您都必须调用指定的初始化程序。上面引用的文档不正确。
2)一个类的指定初始化器调用超类的非指定初始化器?
如果非指定的初始化器由超级提供并实现调用指定的初始化器,那么在父级上调用任何初始化器绝对没有问题。
先前的答案看起来您必须在自己的代码中基本上实现所有超类构造函数,而无需代码。错误的。这就是存在超类初始值设定项的原因,这样您就可以在没有代码的情况下安全地扩展它们。