擴(kuò)展 就是為一個(gè)已有的類围俘、結(jié)構(gòu)體、枚舉類型或者協(xié)議類型添加新功能漾抬。
這包括在沒有權(quán)限獲取原始源代碼的情況下擴(kuò)展類型的能力(即 逆向建模)。
擴(kuò)展和 Objective-C 中的分類類似纳令。(與 Objective-C 不同的是,Swift 的擴(kuò)展沒有名字平绩。)
Swift 中的擴(kuò)展可以:
? 添加計(jì)算型屬性和計(jì)算型類型屬性
? 定義實(shí)例方法和類型方法
? 提供新的構(gòu)造器
? 定義下標(biāo)
? 定義和使用新的嵌套類型
? 使一個(gè)已有類型符合某個(gè)協(xié)議
注意:
擴(kuò)展可以為一個(gè)類型添加新的功能,但是不能重寫已有的功能捏雌。
1跃赚、擴(kuò)展語法
使用關(guān)鍵字 extension 來聲明擴(kuò)展:
class SomeType {
}
extension SomeType {
// 為 SomeType 添加的新功能寫到這里
}
//可以通過擴(kuò)展來擴(kuò)展一個(gè)已有類型性湿,使其采納一個(gè)或多個(gè)協(xié)議:
extension SomeType: SomeProtocol, AnotherProctocol {
// 協(xié)議實(shí)現(xiàn)寫到這里
}
2满败、計(jì)算型屬性
擴(kuò)展可以為已有類型添加計(jì)算型實(shí)例屬性和計(jì)算型類型屬性:
下面的例子為 Swift 的內(nèi)建 Double 類型添加了五個(gè)計(jì)算型實(shí)例屬性,從而提供與距離單位協(xié)作的基本支持:
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”
這些屬性是只讀的計(jì)算型屬性葫录,為了更簡潔,省略了 get 關(guān)鍵字。
它們的返回值是 Double 骇扇,而且可以用于所有接受 Double 值的數(shù)學(xué)計(jì)算中:
let aMarathon = 42.km + 195.m
print("A marathon is \(aMarathon) meters long")
// 打印 “A marathon is 42195.0 meters long”
注意
擴(kuò)展可以添加新的計(jì)算型屬性摔竿,但是不可以添加存儲(chǔ)型屬性少孝,也不可以為已有屬性添加屬性觀察器继低。
3、構(gòu)造器
擴(kuò)展可以為已有類型添加新的構(gòu)造器
下面的例子定義了一個(gè)用于描述幾何矩形的結(jié)構(gòu)體 Rect 稍走。
這個(gè)例子同時(shí)定義了兩個(gè)輔助結(jié)構(gòu)體 Size 和 t ,它們都把 0.0 作為所有屬性的默認(rèn)值:
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()
}
let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
你可以提供一個(gè)額外的接受指定中心點(diǎn)和大小的構(gòu)造器來擴(kuò)展 Rect 結(jié)構(gòu)體:
pextension 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)
}}</pre>
這個(gè)新的構(gòu)造器首先根據(jù)提供的 center 和 size 的值計(jì)算一個(gè)合適的原點(diǎn)粱胜。
然后調(diào)用該結(jié)構(gòu)體的逐一成員構(gòu) 造器 init(origin:size:) 焙压,該構(gòu)造器將新的原點(diǎn)和大小的值保存到了相應(yīng)的屬性中:
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// centerRect 的原點(diǎn)是 (2.5, 2.5)抑钟,大小是 (3.0, 3.0)
4幻件、方法
擴(kuò)展可以為已有類型添加新的實(shí)例方法和類型方法绰沥。
下面的例子為 Int 類型添加了一個(gè)名為 repetitions 的實(shí)例方法:
extension Int {
func repetitions(task: () -> Void) {
for _ in 0..<self {
task()
}
}
}
這個(gè) repetitions(task:) 方法接受一個(gè) () -> Void 類型的單參數(shù)揪利,表示沒有參數(shù)且沒有返回值的函數(shù)狠持。
定義該擴(kuò)展之后,你就可以對(duì)任意整數(shù)調(diào)用 repetitions(task:) 方法甜刻,將閉包中的任務(wù)執(zhí)行整數(shù)對(duì)應(yīng)的次數(shù):
3.repetitions(task: {
print("Hello!")
})
// Hello!
// Hello!
// Hello!
可以使用尾隨閉包讓調(diào)用更加簡潔:
3.repetitions {
print("Goodbye!")
}
// Goodbye!
// Goodbye!
// Goodbye!
可變實(shí)例方法
通過擴(kuò)展添加的實(shí)例方法也可以修改該實(shí)例本身。
結(jié)構(gòu)體和枚舉類型中修改 self 或其屬性的方法必須將該實(shí)例方法標(biāo)注為 mutating 傻铣,正如來自原始實(shí)現(xiàn)的可變方法一樣非洲。
//下面的例子為 Swift 的 Int 類型添加了一個(gè)名為 square 的可變方法蜕径,用于計(jì)算原始值的平方值:
extension Int {
mutating func square() {
self = self * self
}
}
var someInt = 3 someInt.square()
// someInt 的值現(xiàn)在是 9*/
5兜喻、下標(biāo)
擴(kuò)展可以為已有類型添加新下標(biāo)。
這個(gè)例子為 Swift 內(nèi)建類型 Int 添加了一個(gè)整型下標(biāo)帕识。該下標(biāo) [n] 返回十進(jìn)制數(shù)字從右向左數(shù)的第 n 個(gè)數(shù)字:
? 123456789[0] 返回 9
? 123456789[1] 返回 8
......以此類推遂铡。
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
如果該 Int 值沒有足夠的位數(shù)肮疗,即下標(biāo)越界族吻,那么上述下標(biāo)實(shí)現(xiàn)會(huì)返回 0 超歌,猶如在數(shù)字左邊自動(dòng)補(bǔ) 0 :
746381295[9]
// 返回 0蒂教,即等同于:
0746381295[9]