介绍
- 可以给现有的类、结构体、枚举类型、协议添加新的功能。
- 扩展可以:
- 添加计算属性
- 定义方法
- 提供新的构造函数
- 使现有的类型遵守某协议
- 使用
extension
关键字实现扩展。
语法
- 直接扩展某个类型
extension SomeType {
// new functionality to add to SomeType goes here
}
- 扩展某个类型以遵守一个或多个协议,但不能是继承某个类。
extension SomeType: SomeProtocol, AnotherProtocol {
// implementation of protocol requirements goes here
}
扩展计算属性
- 扩展可以向已有的类型添加计算实例属性和计算类型属性。
extension Double {
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
}
25.0.km
25.0.m
25.0.cm
25.0.mm
扩展构造函数
- 对于结构体,可直接添加新的构造函数。
struct Animal {
var species: String
init(species: String) {
self.species = species
}
}
extension Animal {
init(name: String) {
self.init(species:name)
}
}
- 对于类,只能添加新的便利构造函数。
class Animal {
var species: String
init(species: String) {
self.species = species
}
}
extension Animal {
convenience init(name: String) {
self.init(species:name)
}
}
扩展方法
- 扩展可以为已有的类型添加新的实例方法和类型方法。
class Student {
}
extension Student {
// 实例方法
func play(){
print("play")
}
// 类型方法
class func study(){
print("study")
}
}
let stu = Student()
stu.play()
Student.study()
扩展mutating方法
- 扩展结构体,如果要修改属性的值,必须在方法面前加上
mutating
。
struct Student {
var age: Int = 10
}
extension Student {
// 实例方法
mutating func play(){
age = 20
print("play")
}
}
// 此时要用var
var stu = Student()
stu.play()
面向协议编程POP
为什么面向协议?
假如有类继承关系如下:B、C 继承自 A,B1、B2 继承自 B,C1、C2 继承自 C。如果 B1 和 C2 具有某些共同特性,可以有两种做法:
- 找到 B1 和 C2 的最近祖先 A,然后在 A 中添加共同特性代码,这样做的结果是 A 的代码会越来越庞大臃肿,维护起来非常困难。
- 声明一个具有共同特性的协议,让 B1 和 C2 实现该协议,这样其实等于相同的代码写了两次,造成代码的重复。
- 使用协议扩展,它能够为协议中规定的方法提供默认实现。因此声明一个具有共同特性的协议,扩展该协议给出共同特性的实现,然后让 B1 和 C2 实现该协议,既不影响类的继承结构,也不需要写重复代码。
Swift如何实现?
针对某个需要实现的功能,可以使用协议定义出接口,然后利用协议扩展提供默认的实现。需要这个功能,只需要声明遵守了这个协议即可,遵守某个协议的对象调用协议声明的方法时,如果遵守者本身没有提供实现,协议扩展提供的默认实现会被调用。
- 案例:如果有100个协议的遵守者实现都一样,会有大量重复代码。
protocol Eatable {
func eat()
}
// 遵守协议
class Person: Eatable {
func eat() {
print("吃饭了")
}
}
var p = Person()
p.eat()
- 改进:在协议的扩展中给出方法的默认实现,则协议遵守者中可省略。
extension Eatable {
func eat() {
print("吃饭了")
}
}
class Person: Eatable {
}
var p = Person()
p.eat()
- 如果某个遵守者需要独特的实现,自己再实现协议中的方法即可。
class Person: Eatable {
func eat() {
print("人要吃饭了")
}
}
var p = Person()
p.eat()