指定的初始化程序,请澄清。

Designated Initializer, clarify please.

现在这个问题困扰了我很长一段时间,我真的需要有人为我澄清这个问题。

1) 当被子classed 初始化方法调用时,编译器如何确定指定的初始化方法?因为它据说是覆盖率最高的。

2) 当 subclass 使用多个初始化方法时,每个 class 是否都有自己指定的初始化方法?回答问题 2 也有助于理解这一点。

3) 当多个 class 确实有一个指定的初始化器时,其他初始化方法如何在它们的 class 中调用指定的初始化器?为什么他们也不调用任何其他初始化程序?为什么要指定初始化程序?它有什么特别之处?

  1. 编译器没有以任何方式检测到它。为了让编译器知道是否指定了初始化程序,您必须使用 NS_DESIGNATED_INITIALIZER 宏对其进行注解。

  2. 如果 class 有一个初始化器,它总是也有一个指定的初始化器。它实际上可以有多个指定的初始值设定项。如果没有指定的初始值设定项,您根本无法拥有 class 。指定和方便之间的区别非常简单。指定初始化器调用 [super init...](调用超级class 初始化器),而方便调用 [self init...](调用相同 class 的另一个初始化器)。

  3. 便利初始化程序使用 [self init...] 调用指定的初始化程序。指定的初始值设定项并不特殊。它们实际上是最基本的初始化器。他们做了两件事 - 他们初始化父级(使用 [super init...])然后初始化需要的东西(例如属性的默认值等)。便利初始化器是一种特殊的——它们是指定初始化器的扩展。他们调用指定的初始化器并做更多的事情。例如 -initWithStyle: 将是一个指定的初始化器,它将一个对象初始化为特定的样式。 -initWithStyle:andFrame: 会做同样的事情,但它还会将 frame 属性 设置为特定值。如果 -initWithStyle:andFrame: 是使用 [self initWithStyle:... andFrame:...] 实现的,那么它是一个方便的初始化程序。

在 Objective-C 中,class 的指定初始化程序是负责正确初始化 class 以将其置于适当状态以供使用的方法。代码中没有任何内容将其标记为指定的初始值设定项,因此通常在头文件中对此进行注释。由使用或扩展 class 的开发人员来确定哪个方法是指定的初始化程序(通常是 init 或以 init 为前缀)并相应地编写代码。如果 class 没有正确记录并且其源代码不可用,这可能会导致误用 class,这也是 Swift 试图解决的缺点之一。因此,为了解决您的问题...

  1. 指定的初始值设定项不是由编译器确定的。一个 subclass 也应该有一个指定的初始化器,它在某个时候调用 super 的指定初始化器。
  2. 每个 class 都应该清楚地说明(通过注释或文档)哪个初始化程序打算用作指定的初始化程序。由使用 class 的开发人员来确保调用指定的初始化程序。由 class 本身的开发人员来确保按预期调用 super 的指定初始化程序。但是,如果 classes 编写得当,任何初始化方法 应该 调用指定的初始化程序。但是,编译器不保证。
  3. 其他 init 方法需要适当编码以通过 [self init...][super init...] 调用指定的初始化程序。同样,由您决定如何使用 class 并适当地使用或扩展它。

指定初始化器是执行 "heavy lifting" 以准备 class 的新实例以供使用的方法。其他初始化程序称为便利初始化程序,通常用于提供较短的签名和隐含的默认值,因为您不能为 Objective-C 方法签名指定默认参数值。

在大多数情况下,如果 class 写得正确,您真的不必太担心,因为所有便利初始化器最终都应该调用指定的初始化器。

在 Swift 的开发过程中对此进行了很多思考,即使您不打算学习它,也应该继续阅读 Swift Initializers,因为它会给您带来好处深入了解正确的初始化链,然后您可以使用它来指导您在 Objective-C.

中创建初始化程序

更新: 从 Xcode 6 开始,指定的初始值设定项可以这样标记,通常是通过 NS_DESIGNATED_INITIALIZER 宏。这有助于强制执行正确编写的 classes,并且是从 Swift 带回到 Objective-C 的东西。查看 iOS Designated Initializers : Using NS_DESIGNATED_INITIALIZER