2

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

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

2)当使用多个init方法进行子类化时,每个类都有自己指定的初始化方法吗?对问题 2 的回答也有助于理解这一点。

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

4

2 回答 2

2

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

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

指定的初始化程序是执行“繁重”工作以准备类的新实例以供使用的方法。其他初始化程序称为便利初始化程序,通常用于提供具有隐含默认值的较短签名,因为您无法为 Objective-C 方法签名指定默认参数值。

在大多数情况下,如果一个类被正确编写,你真的不必太担心,因为所有便利初始化程序最终都会调用指定的初始化程序。

在 Swift 的开发过程中对此进行了很多思考,即使您不打算学习它,您也应该阅读Swift Initializers,因为它可以让您深入了解正确的初始化链,然后您可以使用指导您在 Objective-C 中创建初始化程序。

更新:从 Xcode 6 开始,指定的初始化器可以这样标记,通常是通过NS_DESIGNATED_INITIALIZER宏。这有助于强制执行正确编写的类,并且是从 Swift 带回 Objective-C 的东西。查看iOS 指定初始化程序:使用 NS_DESIGNATED_INITIALIZER

于 2015-08-30T00:25:16.580 回答
2
  1. 编译器不会以任何方式检测到它。为了让编译器知道是否指定了初始化程序,您必须使用NS_DESIGNATED_INITIALIZER宏对其进行注释。

  2. 如果一个类有一个初始化器,它也总是有一个指定的初始化器。它实际上可以有多个指定的初始化器。你根本不可能有一个没有指定初始化程序的类。指定和便利之间的区别非常简单。指定初始化程序调用[super init...](调用超类初始化程序),而便利调用[self init...](调用同一类的另一个初始化程序)。

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

于 2015-08-30T00:01:09.640 回答