介绍

  • 可以给现有的类、结构体、枚举类型、协议添加新的功能。
  • 扩展可以:
  • 添加计算属性
  • 定义方法
  • 提供新的构造函数
  • 使现有的类型遵守某协议
  • 使用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 具有某些共同特性,可以有两种做法:

  1. 找到 B1 和 C2 的最近祖先 A,然后在 A 中添加共同特性代码,这样做的结果是 A 的代码会越来越庞大臃肿,维护起来非常困难。
  2. 声明一个具有共同特性的协议,让 B1 和 C2 实现该协议,这样其实等于相同的代码写了两次,造成代码的重复。
  3. 使用协议扩展,它能够为协议中规定的方法提供默认实现。因此声明一个具有共同特性的协议,扩展该协议给出共同特性的实现,然后让 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()