1. 概述
扩展用于给已经存在的类、枚举、结构体添加新的功能。Swift中的扩展(extensions)与Objective-C中的分类(categories)的类似,但不同点在于,扩展没有名字。
扩展有如下功能:
- 1)增加 computed属性和静态的computed属性
- 2)定义实例方法 instance methods 和 类型方法type methods(比如类方法)
- 3)提供新的构造器
- 4)定义下标
- 5)定义和使用新的嵌套类型
- 6)使某个已存在的类型符合某个协议( 原话:Make an existing type conform to a protocol)
注意:扩展可以给一个类型增加功能,但是它不能覆盖已经存在的功能。
2. 扩展的语法
使用 extention 关键字定义扩展
extension SomeType { // new functionality to add to SomeType goes here }
可以扩展一个已经存在的类型,使它可以适用一个或多个协议:
extension SomeType: SomeProtocol, AnotherProtocol { // 在这里实现协议的方法 }
3. Computed 属性
扩展可以给一个已存在的类型增加Computed属性,这个Computed属性可以实例属性,也可以是类型属性(computed instance properties and computed type properties)。
下面的例子给Double类型增加了5个computed instance properties:
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 println("One inch is \(oneInch) meters") // prints "One inch is 0.0254 meters" let threeFeet = 3.ft println("Three feet is \(threeFeet) meters") // prints "Three feet is 0.914399970739201 meters"
let aMarathon = 42.km + 195.m println("A marathon is \(aMarathon) meters long") // prints "A marathon is 42195.0 meters long"
注意:扩展只能增加新的Computed属性,不能增加存储属性,不能给已经存在的属性增加属性监视器。
4. 构造器 Initializers
扩展可以给已存在的类型增加构造器。
注意1:扩展只能给类增加 convenience构造器,不能增加 designated构造器,不能增加析构器。designated构造器和析构器必须在类定义时就提供,不能通过扩展提供。
注意2:如果你通过扩展给值类型(即枚举和结构体)提供一个为所有stored属性提供默认值的构造器,并且这个值类型没有定义任何其他的构造器,那么你可以在你扩展的构造器中使用值类型默认的构造器和成员组个初始化构造器。
如下代码定义了几个结构体:
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为所有属性提供了默认值,所以编译器会自动为他提供一个默认构造器和一个成员逐个初始化构造器(参见十三、初始化):
let defaultRect = Rect() let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 5.0, height: 5.0))
如果你想让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) } }
那么:
let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0)) // centerRect‘s origin is (2.5, 2.5) and its size is (3.0, 3.0)
注意:如果你在扩展中提供构造器,你有责任确保一旦构造器执行完毕,所有的实例被完全初始化了。
5. 方法 Methods
可以在扩展中给已存在的类型增加新的实例方法 instance methods 和 类型方法type methods(比如类方法):
extension Int { func repetitions(task: () -> ()) { for i in 0..<self { task() } } }
上面的函数只有一个参数 task: () -> (),没有返回值。
调用扩展的方法:
3.repetitions({ println("Hello!") }) // Hello! // Hello! // Hello!
由于参数在最后,可以使用尾部闭包 trailing closure(详见六、闭包) 的写法:
3.repetitions { println("Goodbye!") } // Goodbye! // Goodbye! // Goodbye!
6、可变的实例方法 Mutating Instance Methods
扩展中定义的 Instance methods 可以定义为 mutate ,即可以改变它自身。结构体和枚举的方法如果要改变self,或者自己的属性时,必须将方法定义为mutating 。
看如下代码:
extension Int { mutating func square() { self = self * self } } var someInt = 3 someInt.square() // someInt is now 9
7、下标 Subscripts
扩展可以给已存在的类型增加下标:
extension Int { subscript(var digitIndex: Int) -> Int { var decimalBase = 1 while digitIndex > 0 { decimalBase *= 10 --digitIndex } return (self / decimalBase) % 10 } } 746381295[0] // returns 5 746381295[1] // returns 9 746381295[2] // returns 2 746381295[8] // returns 7
8、嵌套类型 Nested Types
扩展可以给一个已存在的类、结构体、枚举增加一个新的嵌套类型:
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 } } }
那么:
func printIntegerKinds(numbers: [Int]) { for number in numbers { switch number.kind { case .Negative: print("- ") case .Zero: print("0 ") case .Positive: print("+ ") } } print("\n") } printIntegerKinds([3, 19, -27, 0, -6, 0, 7]) // prints "+ + - 0 - 0 +"
因为number.kind已知为Int.kind类型,所以Int.kind的成员的值可以再switch中使用简写形式,比如.Negative,而不是Int.Kind.Negative
。