鍍金池/ 教程/ iOS/ 擴展
特性(Attributes)
Access Control 權限控制的黑與白
基本運算符(Basic Operators)
基礎部分(The Basics)
閉包(Closures)
擴展
泛型參數(shù)(Generic Parameters and Arguments)
訪問控制和 protected
語句(Statements)
模式(Patterns)
WWDC 里面的那個“大炮打氣球”
關于語言參考(About the Language Reference)
語法總結(jié)(Summary of the Grammar)
嵌套類型
類型(Types)
Swift 初見(A Swift Tour)
泛型
枚舉(Enumerations)
高級運算符
繼承
析構(gòu)過程
關于 Swift(About Swift)
訪問控制
類和結(jié)構(gòu)體
內(nèi)存安全
Swift 與 C 語言指針友好合作
協(xié)議
屬性(Properties)
可選類型完美解決占位問題
錯誤處理
字符串和字符(Strings and Characters)
聲明(Declarations)
自動引用計數(shù)
Swift 里的值類型與引用類型
表達式(Expressions)
Swift 文檔修訂歷史
造個類型不是夢-白話 Swift 類型創(chuàng)建
歡迎使用 Swift
詞法結(jié)構(gòu)(Lexical Structure)
集合類型(Collection Types)
下標
方法(Methods)
可選鏈式調(diào)用
版本兼容性
類型轉(zhuǎn)換
構(gòu)造過程
The Swift Programming Language 中文版
函數(shù)(Functions)
Swift 教程
控制流(Control Flow)

擴展


1.0 翻譯:lyuka 校對:Hawstein

2.0 翻譯+校對:shanks

2.1 校對:shanks

2.2 翻譯+校對:SketchK 2016-05-16 3.0.1,shanks,2016-11-13

4.0 校對:kemchenj 2017-09-21

4.1 翻譯+校對:mylittleswift

本頁包含內(nèi)容:

擴展 就是為一個已有的類、結(jié)構(gòu)體、枚舉類型或者協(xié)議類型添加新功能。這包括在沒有權限獲取原始源代碼的情況下擴展類型的能力(即 逆向建模 )。擴展和 Objective-C 中的分類類似。(與 Objective-C 不同的是,Swift 的擴展沒有名字。)

Swift 中的擴展可以:

  • 添加計算型屬性和計算型類型屬性
  • 定義實例方法和類型方法
  • 提供新的構(gòu)造器
  • 定義下標
  • 定義和使用新的嵌套類型
  • 使一個已有類型符合某個協(xié)議

在 Swift 中,你甚至可以對協(xié)議進行擴展,提供協(xié)議要求的實現(xiàn),或者添加額外的功能,從而可以讓符合協(xié)議的類型擁有這些功能。你可以從協(xié)議擴展獲取更多的細節(jié)。

注意

擴展可以為一個類型添加新的功能,但是不能重寫已有的功能。

擴展語法

使用關鍵字 extension 來聲明擴展:

extension SomeType {
    // 為 SomeType 添加的新功能寫到這里
}

可以通過擴展來擴展一個已有類型,使其采納一個或多個協(xié)議。在這種情況下,無論是類還是結(jié)構(gòu)體,協(xié)議名字的書寫方式完全一樣:

extension SomeType: SomeProtocol, AnotherProctocol {
    // 協(xié)議實現(xiàn)寫到這里
}

通過這種方式添加協(xié)議一致性的詳細描述請參閱利用擴展添加協(xié)議一致性

注意

如果你通過擴展為一個已有類型添加新功能,那么新功能對該類型的所有已有實例都是可用的,即使它們是在這個擴展定義之前創(chuàng)建的。

計算型屬性

擴展可以為已有類型添加計算型實例屬性和計算型類型屬性。下面的例子為 Swift 的內(nèi)建 Double 類型添加了五個計算型實例屬性,從而提供與距離單位協(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”

這些計算型屬性表達的含義是把一個 Double 值看作是某單位下的長度值。即使它們被實現(xiàn)為計算型屬性,但這些屬性的名字仍可緊接一個浮點型字面值,從而通過點語法來使用,并以此實現(xiàn)距離轉(zhuǎn)換。

在上述例子中,Double1.0 用來表示“1米”。這就是為什么計算型屬性 m 返回 self,即表達式 1.m 被認為是計算 Double1.0。

其它單位則需要一些單位換算。一千米等于 1,000 米,所以計算型屬性 km 要把值乘以 1_000.00 來實現(xiàn)千米到米的單位換算。類似地,一米有 3.28024 英尺,所以計算型屬性 ft 要把對應的 Double 值除以 3.28024 來實現(xiàn)英尺到米的單位換算。

這些屬性是只讀的計算型屬性,為了更簡潔,省略了 get 關鍵字。它們的返回值是 Double,而且可以用于所有接受 Double 值的數(shù)學計算中:

let aMarathon = 42.km + 195.m
print("A marathon is \(aMarathon) meters long")
// 打印 “A marathon is 42195.0 meters long”

注意

擴展可以添加新的計算型屬性,但是不可以添加存儲型屬性,也不可以為已有屬性添加屬性觀察器。

構(gòu)造器

擴展可以為已有類型添加新的構(gòu)造器。這可以讓你擴展其它類型,將你自己的定制類型作為其構(gòu)造器參數(shù),或者提供該類型的原始實現(xiàn)中未提供的額外初始化選項。

擴展能為類添加新的便利構(gòu)造器,但是它們不能為類添加新的指定構(gòu)造器或析構(gòu)器。指定構(gòu)造器和析構(gòu)器必須總是由原始的類實現(xiàn)來提供。

注意

如果你使用擴展為一個值類型添加構(gòu)造器,同時該值類型的原始實現(xiàn)中未定義任何定制的構(gòu)造器且所有存儲屬性提供了默認值,那么我們就可以在擴展中的構(gòu)造器里調(diào)用默認構(gòu)造器和逐一成員構(gòu)造器。 正如在值類型的構(gòu)造器代理中描述的,如果你把定制的構(gòu)造器寫在值類型的原始實現(xiàn)中,上述規(guī)則將不再適用。

下面的例子定義了一個用于描述幾何矩形的結(jié)構(gòu)體 Rect。這個例子同時定義了兩個輔助結(jié)構(gòu)體 SizePoint,它們都把 0.0 作為所有屬性的默認值:

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()
}

因為結(jié)構(gòu)體 Rect 未提供定制的構(gòu)造器,因此它會獲得一個逐一成員構(gòu)造器。又因為它為所有存儲型屬性提供了默認值,它又會獲得一個默認構(gòu)造器。詳情請參閱默認構(gòu)造器。這些構(gòu)造器可以用于構(gòu)造新的 Rect 實例:

let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
    size: Size(width: 5.0, height: 5.0))

你可以提供一個額外的接受指定中心點和大小的構(gòu)造器來擴展 Rect 結(jié)構(gòu)體:

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)
    }
}

這個新的構(gòu)造器首先根據(jù)提供的 centersize 的值計算一個合適的原點。然后調(diào)用該結(jié)構(gòu)體的逐一成員構(gòu)造器 init(origin:size:),該構(gòu)造器將新的原點和大小的值保存到了相應的屬性中:

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
    size: Size(width: 3.0, height: 3.0))
// centerRect 的原點是 (2.5, 2.5),大小是 (3.0, 3.0)

注意

如果你使用擴展提供了一個新的構(gòu)造器,你依舊有責任確保構(gòu)造過程能夠讓實例完全初始化。

方法

擴展可以為已有類型添加新的實例方法和類型方法。下面的例子為 Int 類型添加了一個名為 repetitions 的實例方法:

extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }
}

這個 repetitions(task:) 方法接受一個 () -> Void 類型的單參數(shù),表示沒有參數(shù)且沒有返回值的函數(shù)。

定義該擴展之后,你就可以對任意整數(shù)調(diào)用 repetitions(task:) 方法,將閉包中的任務執(zhí)行整數(shù)對應的次數(shù):

3.repetitions({
    print("Hello!")
})
// Hello!
// Hello!
// Hello!

可變實例方法

通過擴展添加的實例方法也可以修改該實例本身。結(jié)構(gòu)體和枚舉類型中修改 self 或其屬性的方法必須將該實例方法標注為 mutating,正如來自原始實現(xiàn)的可變方法一樣。

下面的例子為 Swift 的 Int 類型添加了一個名為 square 的可變方法,用于計算原始值的平方值:

extension Int {
    mutating func square() {
        self = self * self
    }
}
var someInt = 3
someInt.square()
// someInt 的值現(xiàn)在是 9

下標

擴展可以為已有類型添加新下標。這個例子為 Swift 內(nèi)建類型 Int 添加了一個整型下標。該下標 [n] 返回十進制數(shù)字從右向左數(shù)的第 n 個數(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
746381295[2]
// 返回 2
746381295[8]
// 返回 7

如果該 Int 值沒有足夠的位數(shù),即下標越界,那么上述下標實現(xiàn)會返回 0,猶如在數(shù)字左邊自動補 0

746381295[9]
// 返回 0,即等同于:
0746381295[9]

嵌套類型

擴展可以為已有的類、結(jié)構(gòu)體和枚舉添加新的嵌套類型:

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 添加了嵌套枚舉。這個名為 Kind 的枚舉表示特定整數(shù)的類型。具體來說,就是表示整數(shù)是正數(shù)、零或者負數(shù)。

這個例子還為 Int 添加了一個計算型實例屬性,即 kind,用來根據(jù)整數(shù)返回適當?shù)?Kind 枚舉成員。

現(xiàn)在,這個嵌套枚舉可以和任意 Int 值一起使用了:

func printIntegerKinds(_ numbers: [Int]) {
    for number in numbers {
        switch number.kind {
        case .negative:
            print("- ", terminator: "")
        case .zero:
            print("0 ", terminator: "")
        case .positive:
            print("+ ", terminator: "")
        }
    }
    print("")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
// 打印 “+ + - 0 - 0 + ”

函數(shù) printIntegerKinds(_:) 接受一個 Int 數(shù)組,然后對該數(shù)組進行迭代。在每次迭代過程中,對當前整數(shù)的計算型屬性 kind 的值進行評估,并打印出適當?shù)拿枋觥?/p>

注意

由于已知 number.kindInt.Kind 類型,因此在 switch 語句中,Int.Kind 中的所有成員值都可以使用簡寫形式,例如使用 .negative 而不是 Int.Kind.negative。