Swift基础学习

Swift3.0初始化(Initialization)

2017-02-27  本文已影响345人  Mustard_Buli

和 OC 的不同,Swift中的构造器(Initializers) 不需要返回一个值。它们的主要功能就是确保新的实例在第一次使用前完成正确的初始化。

存储值的初始赋值(Setting Initial Values for Stored Properties)

类和结构体必须要创建的时候对它们的存储属性进行合适的赋值。存储值不能处于一个未知的状态。

可以在构造器中为存储型属性赋值,也可以在定义属性时为其赋值。

构造器(Initializers)

构造器就是在创建某个特定类型的新实例时被调用,最简单的形式就是不带任何参数:

init() {
    // 构造过程
}
Initializers 🌰

默认属性值(Default Property Values)

注意
如果一个属性总是使用相同的初始值,那么就应该设置一个默认值,而不是在构造器中赋值。虽然效果是一样的,但是前者个简洁、清晰,并且可以自动推到出类型。同时,也能充分利用到默认构造器、构造器继承等特性。

Default Property Values 🌰

自定义初始化(Customizing Initialization)

可以通过输入参数和可选类型的属性来自定义构造过程,也可以在构造过程中修改常量属性。

初始化参数(Initialization Parameters)

可以在定义构造器的时候提供初始化参数,语法和函数(方法)相同:


Initialization Parameters 🌰

参数名称和标签(Parameter Names and Argument Labels)

和函数、方法的参数相同,构造参数也有一个内部名字和一个外部名字。

然而,构造器不会像函数和方法一样在括号前有一个可辨别的名字,因此在调用构造器是,主要就是通过参数名字和类型来确定应该被调用的构造器。所以参数很重要,如果没有提供参数的标签(外部名字),Swift会为构造器的每个参数自动生成一个和内部名字相同的外部名字:


Parameter Names and Argument Labels 🌰

无标签的构造器参数(Initializer Parameters Without Argument Labels)

如果不希望为构造器的某个参数提供外部名字,可以使用下划线(_
)来显式描述它的外部名,以此重写上面所说的默认行为:


Initializer Parameters Without Argument Labels 🌰

可选属性类型(Optional Property Types)

如果定制的类型包含一个逻辑上允许取值为空的存储型属性——无论是因为它无法在初始化时赋值,还是因为它在之后某个时间点可以赋值为空——都需要将它定义为可选类型(optional type)。可选类型的属性将自动初始化为nil,表示这个属性是有意在初始化时设置为空的:


Optional Property Types 🌰

构造过程中常量属性的修改(Assigning Constant Properties During Initialization)

可以在构造过程中的任意时间点给常量属性指定一个值,只要在构造过程结束时是一个确定的值。一旦常量属性被赋值,它将永远不可更改。

注意
对于类的实例,它的常量属性只能在定义它的类的构造过程中修改,不能在子类中修改。

Assigning Constant Properties During Initialization 🌰

默认构造器(Default Initializers)

如果结构体或类的所有属性都有默认值,同时没有自定义的构造器,那么 Swift 会给这些结构体或类提供一个默认构造器(default initializers)。这个默认构造器将简单地创建一个所有属性值都设置为默认值的实例:


Default Initializers 🌰

结构体类型的逐一构造器(Memberwise Initializers for Structure Types)

如果结构体没有提供自定义的构造器,它们将自动获得一个逐一成员构造器,即使结构体的存储型属性没有默认值。

逐一成员构造器是用来初始化结构体新实例里成员属性的快捷方法。在调用逐一成员构造器时,通过与成员属性名相同的参数名进行传值来完成对成员属性的初始赋值。

Memberwise Initializers for Structure Types 🌰

值类型的构造器代理(Initializer Delegation for Value Types)

构造器可以通过其它构造器来完成实例的部分构造过程。这个过程就称为构造器代理,它能减少多个构造器间的代码重复。

构造器代理的实现规则和形式在值类型和类类型中有所不同。值类型(结构体、枚举)不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给自己的其它构造器。
类不一样,它可以继承自其它类,这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。

对于值类型,使用 self.init 在自定义的构造器中引用相同类型中的其它构造器。并且只能在构造器里调用 self.init。

如果为某个值类型定义一个自定义的构造器,将无法访问到默认构造器(如果是结构体,还将无法访问逐一成员构造器)。这种限制可以防止你为值类型增加一个额外的且十分复杂的构造器之后,仍然有人错误的使用自动生成的构造器。

注意
但是如果希望默认构造器、逐一成员构造器以及自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展 (extension) 中,而不是写在值类型的原始定义中。

Memberwise Initializers for Structure Types 🌰

类的继承和初始化(Class Inheritance and Initialization)

类里面的所有存储型属性,包括所有继承自父类的属性,都必须在构造过程中设置初始值。

Swift 为类类型提供了两种类型的构造器来确保实例中所有存储型属性都能获得初始值,它们分别是指定构造器和便利构造器。

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

指定构造器是类中最主要的构造器。一个指定构造器将初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。

类往往有很少的指定构造器,但是通常一个类只有一个。指定初始化是通过 “funnel” 点初始化,并通过初始化过程持续进行了父类链。

每一个类都必须拥有至少一个指定构造器。在某些情况下,许多类通过继承了父类中的指定构造而满足了这个条件。

便利构造器是类中比较次要的、辅助型的构造器。可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值。也可以定义便利构造器来创建一个特殊用途或特定输入值的实例。

当只在必要的时候为类提供便利构造器,比如说某种情况下通过使用便利构造器来快捷调用某个指定构造器,能够节省更多开发时间并让类的构造过程更清晰明了。

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

类的指定构造器的写法跟值类型简单构造器一样:

init(parameters) {
    // statements
}

便利构造器也采用相同样式的写法,但需要在 init 关键字之前放置 convenience 关键字,并使用空格隔开:

convenience init(parameters) {
    statements
}

类的构造器代理规则(Initializer Delegation for Class Types)

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

  1. 指定构造器必须调用其直接父类的指定构造器。
  2. 便利构造器必须调用同一类中定义的其它构造器。
  3. 便利构造器必须最终导致一个指定构造器被调用。

这样更好记:

可以用一张图来表示:


注意
这些规则不会影响类的实例如何创建。任何上图中战士的构造器都可以用来创建完全初始化的实例。这些规则只影响类定义如何实现。

下图中展示了一种涉及四个类的更复杂的类层级结构。它演示了指定构造器是如何在类层级中充当『管道』的作用,在类的构造器链上简化了类之间的相互关系:


两段式初始化(Two-Phase Initialization)

Swift 中类的构造过程包含两个阶段。在第一段,每个存储型属性引入它们的类指定一个初始值。当每个存储型属性的初始值被确定后,第二个阶段开始,它会给每个类一次机会,在新实例准备使用之前进一步定制它们的存储型属性。

使用两段式初始化会让初始化安全,同时在整个类层级结构中给予了每个类完全的灵活性。两段式构造过程可以防止属性值在初始化之前被访问,也可以防止属性被另外一个构造器意外的赋予不同的值。

注意
Swift 的两段式初始化过程和 OC 的初始化类似。最主要的区别在于阶段 1,OC 给每一个属性赋值 0 或空值(比如说 0 或 nil)。Swift 的初始化流程更加灵活,它允许设置定制的初始值,并自如应对某些属性不能以 0 或 nil 作为合法默认值的情况。

上一篇下一篇

猜你喜欢

热点阅读