swift簡單總結(二十八)—— 可選鏈

版本記錄

版本號 時間
V1.0 2017.07.31

前言

我是swift2.0的時候開始接觸的,記得那時候還不是很穩定,公司的項目也都是用oc做的,并不對swift很重視,我自己學了一段時間,到現在swift3.0+已經出來了,自己平時也不寫,忘記的也差不多了,正好項目這段時間已經上線了,不是很忙,我就可以每天總結一點了,希望對自己對大家有所幫助。在總結的時候我會對比oc進行說明,有代碼的我會給出相關比對代碼。
1. swift簡單總結(一)—— 數據簡單值和類型轉換
2. swift簡單總結(二)—— 簡單值和控制流
3. swift簡單總結(三)—— 循環控制和函數
4. swift簡單總結(四)—— 函數和類
5. swift簡單總結(五)—— 枚舉和結構體
6. swift簡單總結(六)—— 協議擴展與泛型
7. swift簡單總結(七)—— 數據類型
8. swift簡單總結(八)—— 別名、布爾值與元組
9. swift簡單總結(九)—— 可選值和斷言
10. swift簡單總結(十)—— 運算符
11. swift簡單總結(十一)—— 字符串和字符
12. swift簡單總結(十二)—— 集合類型之數組
13. swift簡單總結(十三)—— 集合類型之字典
14. swift簡單總結(十四)—— 控制流
15. swift簡單總結(十五)—— 控制轉移語句
16. swift簡單總結(十六)—— 函數
17. swift簡單總結(十七)—— 閉包(Closures)
18. swift簡單總結(十八)—— 枚舉
19. swift簡單總結(十九)—— 類和結構體
20. swift簡單總結(二十)—— 屬性
21. swift簡單總結(二十一)—— 方法
22. swift簡單總結(二十二)—— 下標腳本
23. swift簡單總結(二十三)—— 繼承
24. swift簡單總結(二十四)—— 構造過程
25. swift簡單總結(二十五)—— 構造過程
26. swift簡單總結(二十六)—— 析構過程
27. swift簡單總結(二十七)—— 自動引用計數

可選鏈

可選鏈(Optional Chaining)是一種可以請求和調用屬性、方法和下標腳本的過程,它的可選性體現在請求或者調用的目標可能為空(nil),如果可選的目標有值,那么調用就會成功;相反,如果選擇的目標為空(nil),則這種調用將返回(nil)多次請求或者調用可以被鏈接在一起形成一個鏈,如果任何一個節點為空(nil),多次請求或調用可以被鏈接在一起形成一個鏈,如果任何一個節點為空,將會導致整個鏈失效。

注意swift的可選鏈和OC中的消息為空有些相像,但是swift可以使用在任何類型中,并且失敗與否都可以被檢測到。

下面將從幾個方面進行講解:

  • 可選鏈可替代強制解析
  • 為可選鏈定義模型類
  • 通過調用可選鏈調用屬性
  • 通過可選鏈調用方法
  • 使用可選鏈調用下標腳本
  • 連接多層鏈接
  • 鏈接可選返回值的方法

可選鏈可替代強制解析

??通過在想調用的屬性、方法或下標腳本的可選值(optional value)(非空)后面放一個問號,可以定義一個可選鏈,這一點很像在可選值后面放一個嘆號來強制拆得其封包內的值,它們的主要區別在于當可選值為空時,可選鏈即刻失敗,然而一般的強制解析將會引發運行時錯誤。

??為了反映可選鏈可以調用為空nil,無論你調用的方法、屬性或者下標腳本等返回的值是不是可選值,它的返回結果都是一個可選值,你可以利用這個返回值來檢測你的可選鏈是否調用成功,有返回值即成功,返回nil則失敗。

下面看一下可選鏈和強制解析的不同。

class Person {
    var residence : Residence?
}

class Residence {
    var numberOfRooms = 1
}

Residence有一個numberOfRoomsint類型,如果你創建一個Person的實例,它的residence屬性被定義為了可選類型,此屬性將默認初始化為空。

 let join = Person()

如果你想用嘆號來強制解析這個人的residence屬性numberOfRooms的值,將會引發運行時錯誤,因為這時沒有可供解析的residence值。

let roomCount = join.residence!.numberOfRooms

報錯如下

fatal error: unexpectedly found nil while unwrapping an Optional value
2017-07-31 19:23:38.146670+0800 JJSwift[6648:2415092] fatal error: unexpectedly found nil while unwrapping an Optional value

join.residence不是nil時,會運行通過,并會將roomCount設置一個int類型的合理值,可選鏈提供了另外一種獲得numberOfRooms的方法,利用可選鏈,使用問號代替原來嘆號的位置。

class JJPracticeVC: UIViewController {


    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGray
        
        let join = Person()
        if let roomCount = join.residence?.numberOfRooms {
            print("John has \(roomCount) rooms")
        }
        else {
            print("unable to retrieve the number of rooms")
        }
    }
}

下面看一下打印輸出

unable to retrieve the number of rooms

這就是告訴swift鏈接可選residence?屬性,如果residence存在則取回numberOfRooms的值。這種獲取numberOfRooms的操作,失敗可選鏈會返回Int?或者稱作"可選Int"。


為可選鏈定義模型類

??你可以使用可選鏈來多層調用屬性、方法和下標腳本,這讓你可以利用它們之間的復雜模型來獲取更底層的屬性,并檢查是否可以成功獲取此類底層屬性。

接著看一個簡單例子。

class Person {
    var residence : Residence?
}

class Room {
    let name : String
    init(name: String) {
        self.name = name
    }
}

class Address {
    var buildingName : String?
    var buildingNumber : String?
    var street : String?
    func buildingIdentify() -> String? {
        if (buildingName?.characters.count)! > 0{
            return buildingName
        }
        else if (buildingNumber?.characters.count)! > 0 {
            return buildingNumber
        }
        else{
            return nil
        }
    }
}

class Residence {
    var rooms = [Room]()
    var numberOfRooms : Int{
        return rooms.count
    }

    subscript(i : Int) -> Room{
        return rooms[i]
    }

    func printNumberOfRooms() {
        print("The number of rooms is \(numberOfRooms)")
    }

    var address : Address?
}

通過可選鏈調用屬性

你可以使用可選鏈獲取屬性,并且檢查屬性是否獲取成功,但是,不能使用可選鏈進行屬性賦值。

下面看一個簡單例子。

class JJPracticeVC: UIViewController {


    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGray
        
        let join = Person()
        if let roomCount = join.residence?.numberOfRooms {
            print("John has \(roomCount) rooms")
        }
        else {
            print("unable to retrieve the number of rooms")
        }
    }
}

看輸出結果

unable to retrieve the number of rooms

由于join.residence是空,所以這個可選鏈和之前一樣失敗了,但是不會報錯誤。


通過可選鏈調用方法

??你可以使用可選鏈來調用可選值的方法并檢查方法調用是否成功,即使這個方法沒有返回值,你仍然可以使用可選鏈來達成這一目的。Residence的方法printNumberOfRooms會打印當前numberOfRooms的值,如下:

    func printNumberOfRooms() {
        print("The number of rooms is \(numberOfRooms)")
    }

??你如果利用可選鏈調用此方法,方法返回值類型將是Void?,而不是Void, 因為當通過可選鏈調用方法時返回值總是可選類型,即使這個方法本身沒有定義返回值,你也可以使用if語句來檢查是否能成功調用printNumberOfRooms方法,如果成功調用,printNumberOfRooms方法會隱式的返回Void,如果沒有成功則會返回nil


使用可選鏈調用下標腳本

??可以使用可選鏈嘗試從下標腳本來獲取值并檢索下標腳本的調用是否成功,然而,你不能通過可選鏈來設置下標腳本。

注意:當你使用可選鏈來獲取下標腳本的時候,你應該將問號放在下標腳本括號的前面不是后面,可選鏈問號一般都直接跟在表達式語句的后面。

一般都這么調用

        let join = Person()
        if let firstRoomName = join.residence?[0].name {
            print("\(firstRoomName)")
        }
        else {
            print("unable get")
        }

可選鏈問號就直接跟在join.residence的后面。


鏈接多層鏈接

??你可以將多層可選鏈接連接在一起,可以取模型內最下層的屬性方法和下標腳本,然而,多層可選鏈接不能再添加比已經返回的可選值更多的層。也就是說:如果你試圖獲得的類型不是可選類型,由于使用了可選鏈它將變成可選類型,如果你試圖獲得的類型已經是可選類型,由于可選鏈它也不會提高可選性。

??因此,如果你試圖通過可選鏈獲得Int值,無論使用多少層鏈接返回的總是Int?,相似的,如果你試圖通過可選鏈獲得Int?值,無論使用多少層鏈接返回的總是Int?

class JJPracticeVC: UIViewController {


    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGray
        
        let join = Person()
        
        if let joinStreet = join.residence?.address?.street {
            print("street name is \(joinStreet)")
        }
        else {
                print("unable get")
       }
    }
}

看輸出結果

unable get

上面,join.residence的值包含一個Residence實例,然而,join.residence.address現在是nil,因此,join.residence?.address?.street 調用失敗。


鏈接可選返回值的方法

??前面解釋了如何通過可選鏈來獲取可選類型屬性值,你也可以通過可選鏈調用一個返回可選類型值的方法并按需鏈接該方法的返回值。

??下面的例子中通過可選鏈調用了Address類中的buildingIdentify方法,這個方法的返回值類型是String?,如上所述,這個方法在可選鏈調用后最終的返回值類型依然是String?

        if let buildingIdentify = join.residence?.address?.buildingIdentify() {
            print("building identify is \(buildingIdentify)")
        }
        else {
                print("unable get")
        }

后記

未完,待續~~~

風景
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容