总览
类(Class)作为OOP的一个关键概念是必须要讨论的。类所包含的特性可以从OO的设计方法来阐述:封装,继承,多态和抽象。不同的语言对于类的描述有不同的方案,不过其OO的宗旨与原则是一致的。Swift语言提供了优秀的类支持,Swift 并不需要为类创建独立的接口和实现文件。你所要做的是 在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口。Swift 的构造器无需返回值,它们的主要任务是保证新实例在第一次使用前完成正确的初始化。本文将从以下几个方面来review Swift中关于类的表述:
- 类及其相关的数据结构
- 属性和方法(延迟加载,计算属性,观察器,域)
- 继承(重写方法和属性)
- 构造过程(构造原理)
- 析构过程(析构原理)
属性
构造过程
构造过程是指通过类构造一个对象的过程,这个过程中包括为对象分配内存空间以及初始化对象属性。OC中是通过向对象发送alloc和init消息实现这两步的(注意alloc发向类对象,init发向实例对象)。Swift中构造过程指的是初始化过程(Initialization),它分为两个步骤(two-phase):
- 为每个存储属性指定初始值。
- 在新实例准备使用之前进一步定制它们的存储型属性。
注意:Swift’s two-phase initialization process is similar to initialization in Objective-C. The main difference is that during phase 1, Objective-C assigns zero or null values (such as 0 or nil) to every property. Swift’s initialization flow is more flexible in that it lets you set custom initial values, and can cope with types for which 0 or nil is not a valid default value.[1]
这表明swift的two-phase构造方法比OC更加个性化,此外Swift编译器会执行4种检查以确保two-phase构造安全无误的完成:
- 确保指定构造器(Designed Initializer)中属性初始化完成再调用父类初始化构造器,这也正是上面所提及的Swift与OC构造过程的区别所在。
- 指定构造器先调用父类构造器再向继承的属性赋值。否则指定构造器赋值会被父类构造器覆盖
- 便利构造器(convenience initializer)必须先调用其他构造器,然后再为属性赋值。
- 构造器在第一阶段构造完成之前,不会生成有效实例,所以与实例相关的操作无效。
上面四条指定了构造器的编写规则,规则通过属性赋值与构造器调用的顺序保证了两件事:其一,确保生成有效实例(Designed);其二,构造器中属性赋值不被覆盖。
构造器类型
1. 默认构造器(default initializers)
2. 指定构造器(Designed Initializers)
- 每个类至少有一个指定构造器,可以通过继承父类指定构造器满足这个条件
- 初始化所有属性
- 往上调用父类初始化方法
3. 便利构造器(Convenience Initializers)
- 指定默认属性或创建一个特殊用途的实例
- 需要调用指定初始化方法
- 关键字
convenience
4. 可失败构造器(Failable Initializers)
-
init?
(或init!
)形式的构造器 - 通过
return nil
表达构造失败 - 通过此构造器实例化的对象是optional类型
- 子类可以重写该构造器(重写成正常构造器)
5. 必要构造器
- 子类必须实现该构造器
- 子类父类需用关键字
required
,子类里不用override
关键字
6. 构造器调用规则
- Rule1 指定构造器必须调用其父类的指定构造器。
- Rule2 便利构造器必须调用同类中定义的其它构造器。
- Rule3 便利构造器必须最终导致一个指定构造器被调用。
这些调用规则与OC的构造器调用规则是一致的。一言以蔽之,所有构造器都要指向指定构造器(横向代理),指定构造器要指向父类指定构造器(向上代理),如下图所示[1]。

继承
跟 Objective-C 中的子类不同,Swift 中的子类默认情况下不会继承父类的构造器。Swift 的这种机制可以防止 一个父类的简单构造器被一个更精细的子类继承,并被错误地用来创建子类的实例。通过override
关键字重写父类方法。当满足特定条件时,父类构造器是可以被自动继承的。
- Rule 1 没有指定构造器的类将继承父类的指定构造器
- Rule 2 如果子类提供了所有父类指定构造器的实现(无论继承来的,还是自定义实现的),子类将自动继承父类所有的便利构造器。
Swift官方文档给出这样一个例子:
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
} }
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
} }
下图展示了它们的构造器链(initializer chain)

-
https://docs.swift.org/swift-book/LanguageGuide/Initialization.html "Swift Initialization" ↩ ↩
网友评论