Swift學習之路-Extension

本文首發地址
請在閱讀本文章時,順手將文中的示例代碼在playground中敲一遍,這樣能加深理解!!!
閱讀該文章大約須要:15分鐘
讀完以後你能得到:
一、Extension是什麼
二、它能作什麼javascript

本文所有內容基於Swift版本:3.0.1

Extension的基本語法

extension SomeType {
    // new functionality to add to SomeType goes here
}複製代碼

Tip:擴展能夠爲一個類型添加新的功能,可是不能重寫已有的功能。html

struct Student {
    var name = ""
    var age = 1
    func print() {

    }
}

extension Student {
    //改行會報錯`invalid redeclaration print()`重複聲明print(),重寫變量也是不行的。
    func print() {
    }
}複製代碼

Swift中的Extension能夠作什麼

咱們想知道Extension在Swift中能作些什麼,最直接的方法就是查看Swift的官方文檔了。下面是文檔中指出Extension能作的六個方面。java

  • 添加計算型實例屬性和計算型類型屬性
  • 定義實例方法和類型方法
  • 提供新的構造器
  • 定義下標
  • 定義和使用新的嵌套類型
  • 使已存在的類型遵照某個協議

看完上面Extension能作的六個方面,咱們來逐條解釋說明一下:git

添加計算型實例屬性和計算型類型屬性

首先咱們要了解什麼是計算型屬性,計算型屬性(computed property)不直接存儲值,而是提供一個getter和一個可選的setter,來間接獲取和設置其餘屬性或變量的值。關於更多的計算型屬性的內容請自行查看官方文檔,在此再也不贅述。那麼咱們什麼場景能夠用到這個功能呢?舉一個最多見的例子,當你想訪問某個view的width的時候,一般狀況下你會這麼寫:程序員

view.frame.size.width複製代碼

可是這樣寫很長很不方便,做爲一個懶惰的程序員,這時候你就要想我能不能縮短訪問該屬性的代碼。不要猶豫了騷年,這時候你只須要寫一個UIView的Extension就能夠達到你的目的。github

extension UIView {
    var x: CGFloat {
        set {
            self.frame.origin.x = newValue
        }
        get {
            return self.frame.origin.x
        }
    }

    var y: CGFloat {
        set {
            self.frame.origin.y = newValue
        }
        get {
            return self.frame.origin.y
        }
    }

    var width: CGFloat {
        set {
            self.frame.size.width = newValue
        }
        get {
            return self.frame.size.width
        }
    }
    var height: CGFloat {
        set {
            self.frame.size.height = newValue
        }
        get {
            return self.frame.size.height
        }
    }
}複製代碼

這樣你就能夠經過來訪問該屬性。怎麼樣,有沒有感覺到Extension的便利之處。swift

view.width複製代碼

定義實例方法和類型方法

在你辛辛苦苦寫完一個Student類後,萬惡的產品過來告訴你需求改了,這時雖然你心中有一萬隻草泥馬在奔騰,可是爲了心中那份神聖的程序員的責任感(固然還有餬口的工資),你仍是要修改代碼。若是你想在不改變原始類的基礎上添加功能,那你能夠給Student類添加Extension來解決問題。app

Tip:這裏值得注意的一點是在Swift中,Extension能夠給類和類型添加,好比你也能夠給一個struct添加Extension,而在Objective-C中,你只能給類添加Extension。ui

class Student {
    var name = ""
    var age = 1
}

extension Student {
    func printCurrentStudentName() {
        print(self.name)
    }
}

var jack = Student()
jack.name = "jack"
jack.printCurrentStudentName()複製代碼

提供新的構造器(Initializers)

最多見的Rect一般由originsize來構造初始化,可是若是在你寫完Rect的定義後,你恰恰想要經過center和size來肯定Rect(做爲一個程序員就要有一種做死的精神),那你就要用Extension來給Rect提供一個新的構造器。關於更多關於構造器的信息,請參考官方文檔spa

本例子來源官方文檔

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))複製代碼

經過Extension來給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)
    }
}複製代碼

這樣你就能夠經過新的構造器來初始化Rect。

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)複製代碼

定義下標

經過Swift中的Extension,你能夠給已知類型添加下標。例以下面的例子就是給Int類型添加一個下標,該下標表示十進制數從右向左的第n個數字。

本例子來源官方文檔

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複製代碼

定義和使用新的嵌套類型(nest type)

Extensions能夠給已知的類、結構體、枚舉添加嵌套類型。下面的例子是給Int類型添加一個判斷正負數的Extension,該Extension嵌套一個枚舉。

本例子來源官方文檔

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("- ", terminator: "")
        case .zero:
            print("0 ", terminator: "")
        case .positive:
            print("+ ", terminator: "")
        }
    }
    print("")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
// Prints "+ + - 0 - 0 + "複製代碼

使已存在的類型遵照某個協議

編寫使該類型遵照某個協議的Extension的語法以下:

extension SomeType: SomeProtocol, AnotherProtocol {
    // implementation of protocol requirements goes here
}複製代碼

示例代碼:

protocol StudentProtocol {
    var address: String { get }
}

struct Student {
    var name = ""
    var age = 1

}

extension Student: StudentProtocol {
    var address: String {
        return "address"
    }
}

var jack = Student()
jack.address
//輸出 address複製代碼

若添加Extension的類型已經實現協議中的內容,你能夠寫一個空的Extension來遵照協議:

protocol StudentProtocol {
    var address: String { get }
}

struct Student {
    var address: String {
        return "address"
    }
    var name = ""
    var age = 1
}

extension Student: StudentProtocol {}

var jack = Student()
jack.address
//輸出 address複製代碼

總結

  • Extension能夠爲一個已有的類、結構體、枚舉類型或者協議類型添加新功能。
  • 能夠在沒有權限獲取原始源代碼的狀況下擴展類型的內容
  • Extendion和Objective-C中的Category相似。(OC中的Category有名字,Swift中的擴展沒有名字)

下篇預告:Swift-Protocol

若本文有何錯誤或者不當之處,還望不吝賜教。謝謝!

Swift-Extension的官方文檔

相關文章
相關標籤/搜索