Swift 扩展

假设你想给 Swift 标准库 — 比如说Double类型添加额外的方法, 但是你又不知道Double的实现, 所以你不能直接给它添加功能。 你改怎么办呢?

Swift 设计了一个叫做 Extensions 的功能来处理这样的情况。 Extensions 允许你为已经存在的类型添加功能。你可以扩展结构体、枚举和类。

你可以使用如下结构来扩展类型:

  • 计算型属性
  • 新的初始化方法
  • 协议的遵守
  • 新的方法
  • 嵌入类型

扩展一个已经存在的类型


Swift 的扩展不允许你给已存在的类型添加存储属性, 但可以添加计算型属性。

1
2
3
4
5
6
7
8
9
10
11
12
typealias Velocity = Double
extension Velocity {
var kph: Velocity { return self * 1.60934 }
var mph: Velocity { return self }
}

// 为已存在的类型添加要遵守的协议
protocol VehicleType {
var topSpeed: Velocity { get }
var numberOfDoors: Int { get }
var hasFlatbed: Bool { get }
}

VehicleType声明了三个属性, topSpeed, numberOfDoors 和 hasFlatbed。每个属性都要求遵守该协议的类型只需为该属性实现 getter 方法。遵守该协议的类型需要提供协议中声明的这些属性。

扩展你自己的类型


添加一个自定义的类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
typealias Velocity = Double
extension Velocity {
var kph: Velocity { return self * 1.60934 }
var mph: Velocity { return self }
}
protocol VehicleType {
var topSpeed: Velocity { get }
var numberOfDoors: Int { get }
var hasFlatbed: Bool { get }
}
struct Car {
let make: String
let model: String
let year: Int
let color: String
let nickname: String
var gasLevel: Double {
willSet {
precondition(newValue <= 1.0 && newValue >= 0.0,
} }
"New value must be between 0 and 1.")
}

gasLevel 是一个可变的含有属性观察器的存储属性。每次你想要给 gasLevel设置一个新值的时候都会调用 willSet观察器。precondition()函数确保被赋值给 gasLevel 属性的 newValue 在区间 0到1 之内。

给类添加扩展以使其遵守协议


扩展提供了很好的机制来把相关的功能块儿归为一组。在单个扩展中把相关功能片段归为一组可以让你的代码可读性更好, 并且更容易维护。

下面扩展 Car 类型使其遵守 VeicleType 协议。

1
2
3
4
5
extension Car: VehicleType {
var topSpeed: Velocity { return 180 }
var numberOfDoors: Int { return 4 }
var hasFlatbed: Bool { return false }
}

你在extension的主体里面实现了协议的必要属性。每个属性给了一个简单的 getter, 为了方便, 你仅仅返回简单的默认值。

使用扩展给已存在的类添加 initializer


还记得吗, 结构体给了你一个免费的逐个成员初始化函数, 如果你自己每提供的话。如果你想为你的结构体写一个新的 initializer 函数, 但是又不想失去那个免费的逐个成员初始化函数, 你可以使用扩展为你的类型添加一个 initializer 函数。

下面在新的扩展中给Car添加一个initializer 函数: