iOS Swift No.14 - 构造 3

第十四章 构造

5. Class Inheritance and Initialization (类的继承和构造过程)

类的所有存储属性 - 包括其他任何一个继承自父类的属性 - 必须在构造的过程中分配一个初始值。swift语言为类类型定义了两种构造器用来确保所有的存储属性可以接受初始值,这两种构造器分别是指定构造器(designated initializer)和便利构造器(convenience initializer)。

5.1 Designated Initializer and Convenience Initializer (指定构造器和便利构造器)

指定构造器是类里面的一个主要的构造器。这个指定构造器可以完全构造类里面的属性,斌切还可以调用适当的父类构造器。来继续执行整个构造过程直到父类,一个类至少要有一个指定构造器,类的指定构造器可能会变的越来越少不管怎么说 类至少要有一个指定构造器方便管理。在某些情况下,许多类通过继承了父类中的指定构造器而满足了这个条件。详见自动构造器继承。

便利构造器对一个类来说是一个次要的,辅助支持型的构造器。我们可以定义一个便利构造器,在相同类里面来用便利构造器来调用指定构造器 并用便利构造器的来提供制定构造器的参数从而作为便利构造器的默认参数。也可以用定义一个便利构造器的方式来创建一个提供特殊用图或输入值类型的实例。

5.2 Syntax for Designated and Convenience Initializer (指定和便利构造器的语法)

指定构造器和一般构造器的语法是一样的。类里面只有一个构造器就是指定构造器。

// 指定构造器 
init(parameters) {
    statements
}

便利构造器在指定构造器init关键字前面加上convenience修饰符 用于区分指定和便利构造器。

// 便利构造器
convenience init(parameters) {
    statements
}

5.3 Initializer Delegation for Class Types (类类型的构造器代理)

为了简化指定构造器和便利构造器之间的调用关系,Swift 采用以下三条规则来限制构造器之间的代理调用:

  • 规则 1 :指定构造器必须调用其直接父类的的指定构造器。
    Designated initializer must call a designated initializer from its immediate superclass.
  • 规则 2:便利构造器必须调用同类中定义的其它构造器。
    Convenience initializer must call another initializer from the same class.
  • 规则 3:便利构造器必须最终导致一个指定构造器被调用。
    Convenience initializer must ultimately call a designated initializer.

一个更方便记忆的方法是:

  • 指定构造器必须总是向上代理
  • 便利构造器必须总是横向代理

这些规则可以通过下面图例来说明:

  • 结合上面的规则全面理解类类型中的指定构造器和便利构造器的关系图例!
    在这里插入图片描述
  • 复杂的类的构造器的调用关系图例
    在这里插入图片描述

5.4 Two-Phase Initialization (两段构造过程)

  • Swift语言里面类类型的构造过程包括两段,第一个阶段,每个存储型属性被引入它们的类指定一个初始值。当每个存储型属性的初始值被确定后,第二阶段开始,它给每个类一次机会,在新实例准备使用之前进一步定制它们的存储型属性。
    Class initialization in Swift is a two-phase process. In the first phase, each stored property is assigned an initial value by the class that introduced it. Once the initial state for every stored property has been determined, the second phase begins, and each class is given the opportunity to customize its stored properties further before the new instance is considered ready for use.

  • 这个两段构造结构可以使整个类类型的构造过程更加安全,同时在整个类层级结构中给予了每个类完全的灵活性。两段式构造过程可以防止属性值在初始化之前被访问,也可以防止属性被另外一个构造器意外地赋予不同的值。swift的编译器会执行四种有效的安全检查,用此来确保两段构造过程的完整性 不会在编译执行的时候出错。
    The use of a two-phase initialization process makes initialization safe, while still giving complete flexibility to each class in a class hierarchy. Two-phase initialization prevents property values from being accessed before they are initialized, and prevents property values from being set to a different value by another initializer unexpectedly. Swift’s compiler performs four helpful safety-checks to make sure that two-phase initialization is completed without error

安全检查 1

  • 指定构造器必须保证它所在类引入的所有属性都必须先初始化完成,之后才能将其它构造任务向上代理给父类中的构造器。
    A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.

    如上所述,一个对象的内存只有在其所有存储型属性确定之后才能完全初始化。为了满足这一规则,指定构造器必须保证它所在类引入的属性在它往上代理之前先完成初始化。
    As mentioned above, the memory for an object is only considered fully initialized once the initial state of all of its stored properties is known. In order for this rule to be satisfied, a designated initializer must make sure that all of its own properties are initialized before it hands off up the chain.

安全检查 2

  • 指定构造器必须先向上代理调用父类构造器,然后再为继承的属性设置新值。如果没这么做,指定构造器赋予的新值将被父类中的构造器所覆盖。
    A designated initializer must delegate up to a superclass initializer before assigning a value to an inherited property. If it doesn’t, the new value the designated initializer assigns will be overwritten by the superclass as part of its own initialization

安全检查 3

  • 便利构造器必须先代理调用同一类中的其它构造器,然后再为任意属性赋新值。如果没这么做,便利构造器赋予的新值将被同一类中其它指定构造器所覆盖。
    A convenience initializer must delegate to another initializer before assigning a value to any property (including properties defined by the same class). If it doesn’t, the new value the convenience initializer assigns will be overwritten by its own class’s designated initializer.

安全检查 4

  • 构造器在第一阶段构造完成之前,不能调用任何实例方法,不能读取任何实例属性的值,不能引用 self 作为一个值。
    An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.
  • 类实例在第一阶段结束以前并不是完全有效的。只有第一阶段完成后,该实例才会成为有效实例,才能访问属性
    和调用方法
    The class instance is not fully valid until the first phase ends. Properties can only be accessed, and methods can only be called, once the class instance is known to be valid at the end of the first phase

下面是两段构造过程基于四种安全检查的运作详解

阶段 1

  • 一个指定或便利构造器被一个类所调用
    A designated or convenience initializer is called on a class

  • 完成新实例内存的分配,但此时内存还没有被初始化
    Memory for a new instance of that class is allocated. The memory is not yet initialized.

  • 指定构造器确保其所在类引入的所有存储型属性都已赋初值。存储型属性所属的内存完成初始化
    A designated initializer for that class confirms that all stored properties introduced by that class have a value. the memory for these stored properties is now initialized.

  • 指定构造器将调用父类的构造器,完成父类属性的初始化
    The designated initializer hands off to a superclass initializer to perform the same task for its own stored properties.

  • 这个调用父类构造器的过程沿着构造器链一直往上执行,直到到达构造器链的最顶部。
    This continues up the class inheritance chain until the top of the chain is reached.

  • 当到达了构造器链最顶部,且已确保所有实例包含的存储型属性都已经赋值,这个实例的内存被认为已经完全初始化。此时阶段 1 完成。
    Once the top of the chain is reached, and the final class in the chain has ensured that all of its stored properties have a value, the instance’s memory is considered to be fully initialized, and phase 1 is complete.

阶段 2

  • 从顶部构造器链一直往下,每个构造器链中类的指定构造器都有机会进一步定制实例。构造器此时可以访问 self 、修改它的属性并调用实例方法等等。
    Working back down from the top of the chain, each designated initializer in the chain has the option to customize the instance further. Initializers are now able to access self and can modify its properties, call its instance methods, and so on.
  • 最终,任意构造器链中的便利构造器可以有机会定制实例和使用 self
    Finally, any convenience initializers in the chain have the option to customize the instance and to work with self.

猜你喜欢

转载自blog.csdn.net/weixin_45026183/article/details/105894568