在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ Optional Chaining
方法 - Methods
關(guān)于 Swift
下標(biāo)腳本(Subscripts)
類和結(jié)構(gòu)體
類型轉(zhuǎn)換(Type Casting)
控制流
析構(gòu)過程(Deinitialization)
集合類型 (Collection Types)
構(gòu)造過程(Initialization)
Optional Chaining
枚舉(Enumerations)
自動(dòng)引用計(jì)數(shù)
繼承(Inheritance)
擴(kuò)展(Extensions)
泛型
字符串和字符(Strings and Characters)
函數(shù)(Functions)
高級(jí)運(yùn)算符
訪問控制
基本運(yùn)算符
嵌套類型
閉包(Closures)
協(xié)議
屬性 (Properties)

Optional Chaining

可選鏈(Optional Chaining)是一種可以請(qǐng)求和調(diào)用屬性、方法及下標(biāo)腳本的過程,它的可選性體現(xiàn)于請(qǐng)求或調(diào)用的目標(biāo)當(dāng)前可能為空(nil)。如果可選的目標(biāo)有值,那么調(diào)用就會(huì)成功;相反,如果選擇的目標(biāo)為空(nil),則這種調(diào)用將返回空(nil)。多次請(qǐng)求或調(diào)用可以被鏈接在一起形成一個(gè)鏈,如果任何一個(gè)節(jié)點(diǎn)為空(nil)將導(dǎo)致整個(gè)鏈?zhǔn)А?/p>

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

可選鏈可替代強(qiáng)制解析

通過在想調(diào)用的屬性、方法、或下標(biāo)腳本的可選值(optional value)(非空)后面放一個(gè)問號(hào),可以定義一個(gè)可選鏈。這一點(diǎn)很像在可選值后面放一個(gè)嘆號(hào)來強(qiáng)制拆得其封包內(nèi)的值。它們的主要的區(qū)別在于當(dāng)可選值為空時(shí)可選鏈即刻失敗,然而一般的強(qiáng)制解析將會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤。

為了反映可選鏈可以調(diào)用空(nil),不論你調(diào)用的屬性、方法、下標(biāo)腳本等返回的值是不是可選值,它的返回結(jié)果都是一個(gè)可選值。你可以利用這個(gè)返回值來檢測你的可選鏈?zhǔn)欠裾{(diào)用成功,有返回值即成功,返回nil則失敗。

調(diào)用可選鏈的返回結(jié)果與原本的返回結(jié)果具有相同的類型,但是原本的返回結(jié)果被包裝成了一個(gè)可選值,當(dāng)可選鏈調(diào)用成功時(shí),一個(gè)應(yīng)該返回Int的屬性將會(huì)返回Int?。

下面幾段代碼將解釋可選鏈和強(qiáng)制解析的不同。

首先定義兩個(gè)類PersonResidence

    class Person {
        var residence: Residence?
    }
    class Residence {
        var numberOfRooms = 1
    }

Residence具有一個(gè)Int類型的numberOfRooms,其值為 1。Person具有一個(gè)可選residence屬性,它的類型是Residence?。

如果你創(chuàng)建一個(gè)新的Person實(shí)例,它的residence屬性由于是被定義為可選型的,此屬性將默認(rèn)初始化為空:

    let john = Person()

如果你想使用感嘆號(hào)(!)強(qiáng)制解析獲得這個(gè)人residence屬性numberOfRooms屬性值,將會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤,因?yàn)檫@時(shí)沒有可以供解析的residence值。

    let roomCount = john.residence!.numberOfRooms
    //將導(dǎo)致運(yùn)行時(shí)錯(cuò)誤

當(dāng)john.residence不是nil時(shí),會(huì)運(yùn)行通過,且會(huì)將roomCount 設(shè)置為一個(gè)int類型的合理值。然而,如上所述,當(dāng)residence為空時(shí),這個(gè)代碼將會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。

可選鏈提供了一種另一種獲得numberOfRooms的方法。利用可選鏈,使用問號(hào)來代替原來!的位置:

    if let roomCount = john.residence?.numberOfRooms {
        println("John's residence has \(roomCount) room(s).")
    } else {
        println("Unable to retrieve the number of rooms.")
    }
    // 打印 "Unable to retrieve the number of rooms.

這告訴 Swift 來鏈接可選residence?屬性,如果residence存在則取回numberOfRooms的值。

因?yàn)檫@種嘗試獲得numberOfRooms的操作有可能失敗,可選鏈會(huì)返回Int?類型值,或者稱作“可選Int”。當(dāng)residence是空的時(shí)候(上例),選擇Int將會(huì)為空,因此會(huì)出現(xiàn)無法訪問numberOfRooms的情況。

要注意的是,即使numberOfRooms是非可選IntInt?)時(shí)這一點(diǎn)也成立。只要是通過可選鏈的請(qǐng)求就意味著最后numberOfRooms總是返回一個(gè)Int?而不是Int。

你可以自己定義一個(gè)Residence實(shí)例給john.residence,這樣它就不再為空了:

    john.residence = Residence()

john.residence 現(xiàn)在有了實(shí)際存在的實(shí)例而不是nil了。如果你想使用和前面一樣的可選鏈來獲得numberOfRoooms,它將返回一個(gè)包含默認(rèn)值 1 的Int?

    if let roomCount = john.residence?.numberOfRooms {
        println("John's residence has \(roomCount) room(s).")
    } else {
        println("Unable to retrieve the number of rooms.")
    }
    // 打印 "John's residence has 1 room(s)"。

為可選鏈定義模型類

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

后面的代碼定義了四個(gè)將在后面使用的模型類,其中包括多層可選鏈。這些類是由上面的PersonResidence模型通過添加一個(gè)Room和一個(gè)Address類拓展來。

Person類定義與之前相同。

    class Person {
        var residence: Residence?
    }

Residence類比之前復(fù)雜些。這次,它定義了一個(gè)變量 rooms,它被初始化為一個(gè)Room[]類型的空數(shù)組:

    class Residence {
        var rooms = [Room]()
        var numberOfRooms: Int {
        return rooms.count
        }
        subscript(i: Int) -> Room {
            return rooms[i]
        }
        func printNumberOfRooms() {
            println("The number of rooms is \(numberOfRooms)")
        }
        var address: Address?
    }

因?yàn)?code>Residence存儲(chǔ)了一個(gè)Room實(shí)例的數(shù)組,它的numberOfRooms屬性值不是一個(gè)固定的存儲(chǔ)值,而是通過計(jì)算而來的。numberOfRooms屬性值是由返回rooms數(shù)組的count屬性值得到的。

為了能快速訪問rooms數(shù)組,Residence定義了一個(gè)只讀的下標(biāo)腳本,通過插入數(shù)組的元素角標(biāo)就可以成功調(diào)用。如果該角標(biāo)存在,下標(biāo)腳本則將該元素返回。

Residence中也提供了一個(gè)printNumberOfRooms的方法,即簡單的打印房間個(gè)數(shù)。

最后,Residence定義了一個(gè)可選屬性叫addressaddress?)。Address類的屬性將在后面定義。 用于rooms數(shù)組的Room類是一個(gè)很簡單的類,它只有一個(gè)name屬性和一個(gè)設(shè)定room名的初始化器。

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

這個(gè)模型中的最終類叫做Address。它有三個(gè)類型是String?的可選屬性。前面兩個(gè)可選屬性buildingNamebuildingNumber作為地址的一部分,是定義某個(gè)建筑物的兩種方式。第三個(gè)屬性street,用于命名地址的街道名:

    class Address {
        var buildingName: String?
        var buildingNumber: String?
        var street: String?
        func buildingIdentifier() -> String? {
            if buildingName {
                return buildingName
            } else if buildingNumber {
                return buildingNumber
            } else {
                return nil
            }
        }
    }

Address類還提供了一個(gè)buildingIdentifier的方法,它的返回值類型為String?。這個(gè)方法檢查buildingNamebuildingNumber的屬性,如果buildingName有值則將其返回,或者如果buildingNumber有值則將其返回,再或如果沒有一個(gè)屬性有值,返回空。

通過可選鏈調(diào)用屬性

正如上面“ 可選鏈可替代強(qiáng)制解析”中所述,你可以利用可選鏈的可選值獲取屬性,并且檢查屬性是否獲取成功。然而,你不能使用可選鏈為屬性賦值。

使用上述定義的類來創(chuàng)建一個(gè)人實(shí)例,并再次嘗試后去它的numberOfRooms屬性:

    let john = Person()
    if let roomCount = john.residence?.numberOfRooms {
        println("John's residence has \(roomCount) room(s).")
    } else {
        println("Unable to retrieve the number of rooms.")
    }
    // 打印 "Unable to retrieve the number of rooms。

由于john.residence是空,所以這個(gè)可選鏈和之前一樣失敗了,但是沒有運(yùn)行時(shí)錯(cuò)誤。

通過可選鏈調(diào)用方法

你可以使用可選鏈的來調(diào)用可選值的方法并檢查方法調(diào)用是否成功。即使這個(gè)方法沒有返回值,你依然可以使用可選鏈來達(dá)成這一目的。

ResidenceprintNumberOfRooms方法會(huì)打印numberOfRooms的當(dāng)前值。方法如下:

    func printNumberOfRooms(){
        println(“The number of rooms is \(numberOfRooms)”)
    }

這個(gè)方法沒有返回值。但是,沒有返回值類型的函數(shù)和方法有一個(gè)隱式的返回值類型Void(參見Function Without Return Values)。

如果你利用可選鏈調(diào)用此方法,這個(gè)方法的返回值類型將是Void?,而不是Void,因?yàn)楫?dāng)通過可選鏈調(diào)用方法時(shí)返回值總是可選類型(optional type)。即使這個(gè)方法本身沒有定義返回值,你也可以使用if語句來檢查是否能成功調(diào)用printNumberOfRooms方法:如果方法通過可選鏈調(diào)用成功,printNumberOfRooms的隱式返回值將會(huì)是Void,如果沒有成功,將返回nil

    if john.residence?.printNumberOfRooms?() {
        println("It was possible to print the number of rooms.")
    } else {
        println("It was not possible to print the number of rooms.")
    }
    // 打印 "It was not possible to print the number of rooms."。

使用可選鏈調(diào)用下標(biāo)腳本

你可以使用可選鏈來嘗試從下標(biāo)腳本獲取值并檢查下標(biāo)腳本的調(diào)用是否成功,然而,你不能通過可選鏈來設(shè)置下標(biāo)腳本。

注意:
當(dāng)你使用可選鏈來獲取下標(biāo)腳本的時(shí)候,你應(yīng)該將問號(hào)放在下標(biāo)腳本括號(hào)的前面而不是后面??蛇x鏈的問號(hào)一般直接跟在表達(dá)語句的后面。

下面這個(gè)例子用在Residence類中定義的下標(biāo)腳本來獲取john.residence數(shù)組中第一個(gè)房間的名字。因?yàn)?code>john.residence現(xiàn)在是nil,下標(biāo)腳本的調(diào)用失敗了。

    if let firstRoomName = john.residence?[0].name {
        println("The first room name is \(firstRoomName).")
    } else {
        println("Unable to retrieve the first room name.")
    }
    // 打印 "Unable to retrieve the first room name."。

在下標(biāo)腳本調(diào)用中可選鏈的問號(hào)直接跟在john.residence的后面,在下標(biāo)腳本括號(hào)的前面,因?yàn)?code>john.residence是可選鏈試圖獲得的可選值。

如果你創(chuàng)建一個(gè)Residence實(shí)例給john.residence,且在他的rooms數(shù)組中有一個(gè)或多個(gè)Room實(shí)例,那么你可以使用可選鏈通過Residence下標(biāo)腳本來獲取在rooms數(shù)組中的實(shí)例了:

    let johnsHouse = Residence()
    johnsHouse.rooms += Room(name: "Living Room")
    johnsHouse.rooms += Room(name: "Kitchen")
    john.residence = johnsHouse
    if let firstRoomName = john.residence?[0].name {
        println("The first room name is \(firstRoomName).")
    } else {
        println("Unable to retrieve the first room name.")
    }
    // 打印 "The first room name is Living Room."。

連接多層鏈接

你可以將多層可選鏈連接在一起,可以掘取模型內(nèi)更下層的屬性方法和下標(biāo)腳本。然而多層可選鏈不能再添加比已經(jīng)返回的可選值更多的層。 也就是說:

如果你試圖獲得的類型不是可選類型,由于使用了可選鏈它將變成可選類型。 如果你試圖獲得的類型已經(jīng)是可選類型,由于可選鏈它也不會(huì)提高可選性。

因此:

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

下面的例子試圖獲取johnresidence屬性里的addressstreet屬性。這里使用了兩層可選鏈來聯(lián)系residenceaddress屬性,它們兩者都是可選類型:

    if let johnsStreet = john.residence?.address?.street {
        println("John's street name is \(johnsStreet).")
    } else {
        println("Unable to retrieve the address.")
    }
    // 打印 "Unable to retrieve the address.”。

john.residence的值現(xiàn)在包含一個(gè)Residence實(shí)例,然而john.residence.address現(xiàn)在是nil,因此john.residence?.address?.street調(diào)用失敗。

從上面的例子發(fā)現(xiàn),你試圖獲得street屬性值。這個(gè)屬性的類型是String?。因此盡管在可選類型屬性前使用了兩層可選鏈,john.residence?.address?.street的返回值類型也是String?。

如果你為Address設(shè)定一個(gè)實(shí)例來作為john.residence.address的值,并為addressstreet屬性設(shè)定一個(gè)實(shí)際值,你可以通過多層可選鏈來得到這個(gè)屬性值。

    let johnsAddress = Address()
    johnsAddress.buildingName = "The Larches"
    johnsAddress.street = "Laurel Street"
    john.residence!.address = johnsAddress
    if let johnsStreet = john.residence?.address?.street {
        println("John's street name is \(johnsStreet).")
    } else {
        println("Unable to retrieve the address.")
    }
    // 打印 "John's street name is Laurel Street."。

值得注意的是,“!”符號(hào)在給john.residence.address分配address實(shí)例時(shí)的使用。john.residence屬性是一個(gè)可選類型,因此你需要在它獲取address屬性之前使用!解析以獲得它的實(shí)際值。

鏈接可選返回值的方法

前面的例子解釋了如何通過可選鏈來獲得可選類型屬性值。你也可以通過可選鏈調(diào)用一個(gè)返回可選類型值的方法并按需鏈接該方法的返回值。

下面的例子通過可選鏈調(diào)用了Address類中的buildingIdentifier 方法。這個(gè)方法的返回值類型是String?。如上所述,這個(gè)方法在可選鏈調(diào)用后最終的返回值類型依然是String?

    if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
        println("John's building identifier is \(buildingIdentifier).")
    }
    // 打印 "John's building identifier is The Larches."。

如果你還想進(jìn)一步對(duì)方法返回值執(zhí)行可選鏈,將可選鏈問號(hào)符放在方法括號(hào)的后面:

    if let upper = john.residence?.address?.buildingIdentifier()?.uppercaseString {
        println("John's uppercase building identifier is \(upper).")
    }
    // 打印 "John's uppercase building identifier is THE LARCHES."。

注意:
在上面的例子中,你將可選鏈問號(hào)符放在括號(hào)后面是因?yàn)槟阆胍溄拥目蛇x值是buildingIdentifier方法的返回值,不是buildingIdentifier方法本身。