扩展

扩展可以为一个已有的类、结构体、枚举类型或者协议类型添加新功能

拥有不需要访问被扩展类型源代码就能完成扩展的能力(即逆向建模)

注意

Swift的扩展和OC中的分类功能很相似,但是Swift中的分类是没有名字的

Swift中的扩展可功能:

  • 添加计算型属性和计算类型属性
  • 定义实例方法和类型方法
  • 提供新的构造器
  • 定义下标
  • 定义和使用新的嵌套类型
  • 使一个已有类型符合某个协议

在swift中,甚至可以对协议进行扩展、提供协议其需要的实现,或者添加额外的功能给遵循的类型所使用

注意

扩展只能添加新的功能不能重写已有功能

扩展语法

用关键字extension声明扩展:

extension SomeType {
    // 为 SomeType 添加的新功能写到这里
}

扩展一个已有类型,使其采纳一个或多个协议

extension SomeType: SomeProtocol, AnotherProctocol {
    // 协议实现写到这里
}

注意:

对于一个现有类型,如果定义一个扩展来添加新的功能,那么这个类型的所有实例都可以使用这个新功能。包括那些在扩展定以前就存在的实例。

计算型属性

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 }
    var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("One inch is \(oneInch) meters")
    // 打印 “One inch is 0.0254 meters”
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters")
    // 打印 “Three feet is 0.914399970739201 meters”

扩展Double类型,增加计算型属性,实现距离转换
上面的属性是只读的计算型属性,省略了get关键字

注意:

可以增加新的计算型属性,但是不能增加存储型属性,也不能为已有属性添加属性观察器

构造器

扩展可以为已有类型添加新的构造器。

扩展能为添加新的便利构造器,但是不能为类添加新的指定构造器或者析构器。指定构造器和析构器必须由类的原始实现提供

注意:

如果使用扩展给值类型添加构造器只适用于给所有的存储属性提供默认值,并且没有定义任何自定义构造器,那么你将可以在该值类型扩展的构造器中使用默认构造器和逐一成员构造器。但是如果将构造器写在值类型的原始视线中,那么就属于在扩展中添加构造器

如果通过扩展提供一个新的构造器 那么有责任确保每个通过构造器创建的实例都是初始化完整的

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
}

因为Rect没有指定构造器,存储属性也都有默认值,因此获得一个逐一成员构造器和默认构造器,

extension Rect {
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        //调用结构体的逐一成员构造器
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}

方法

为已有类型添加新的实例方法和类型方法

extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }
}
//为Int类型添加一个名为`repetitions`的实例方法
//这个方法接受一个`()->Void`类型的单参数,没有参数也没有返回值的函数

可变实例方法

扩展中添加的实例方法也可以修改该实例本身,对于值类型即结构体或者枚举修改self或其属性的方法就必须将该实例方法标注为mutating(类似原始实现)

extension Int {
    mutating func square() {
        self = self * self
    }
}

下标

扩展为已有类型添加下标.

extension Int {
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        for _ in 0..<digitIndex {
            decimalBase *= 10
        }
        return (self / decimalBase) % 10
    }
}
746381295[0]
// 返回 5
746381295[1]
// 返回 9
//取的下标越界时自动用0补充
746381295[9]
// 返回 0,即等同于:
0746381295[9]

上面的例子为Int增加下标方法,[n]返回十进制数字从右向左数的第n个数字

嵌套类型

扩展可以为已有的类、结构体和枚举添加新的嵌套类型:

extension Int {
    enum Kind {
    case Negative, Zero, Positive
    }
    var kind: Kind {
        switch self {
        case 0:
            return .Zero
        case let x where x > 0:
            return .Positive
        default:
            return .Negative
        }
    }
}

Int添加了一个嵌套枚举,来表明特定整数的类型,即正数、负数或零