<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                > 1.0 翻譯:[Jasonbroker](https://github.com/Jasonbroker)?校對:[numbbbbb](https://github.com/numbbbbb),?[stanzhai](https://github.com/stanzhai) > > 2.0 翻譯+校對:[lyojo](https://github.com/lyojo) 本頁內容包含: [TOC=2] 可空鏈式調用(Optional Chaining)是一種可以請求和調用屬性、方法及下標的過程,它的可空性體現于請求或調用的目標當前可能為空(nil)。如果可空的目標有值,那么調用就會成功;如果選擇的目標為空(nil),那么這種調用將返回空(nil)。多個連續的調用可以被鏈接在一起形成一個調用鏈,如果其中任何一個節點為空(nil)將導致整個鏈調用失敗。 > 注意: Swift 的可空鏈式調用和 Objective-C 中的消息為空有些相像,但是 Swift 可以使用在任意類型中,并且能夠檢查調用是否成功。 ## 使用可空鏈式調用來強制展開 通過在想調用非空的屬性、方法、或下標的可空值(optional value)后面放一個問號,可以定義一個可空鏈。這一點很像在可空值后面放一個嘆號(!)來強制展開其中值。它們的主要的區別在于當可空值為空時可空鏈式只是調用失敗,然而強制展開將會觸發運行時錯誤。 為了反映可空鏈式調用可以在空對象(nil)上調用,不論這個調用的屬性、方法、下標等返回的值是不是可空值,它的返回結果都是一個可空值。你可以利用這個返回值來判斷你的可空鏈式調用是否調用成功,如果調用有返回值則說明調用成功,返回`nil`則說明調用失敗。 特別地,可空鏈式調用的返回結果與原本的返回結果具有相同的類型,但是被包裝成了一個可空類型值。當可空鏈式調用成功時,一個本應該返回`Int`的類型的結果將會返回`Int?`類型。 下面幾段代碼將解釋可空鏈式調用和強制展開的不同。 首先定義兩個類`Person`和`Residence`。 ~~~ class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 } ~~~ `Residence`有一個`Int`類型的屬性`numberOfRooms`,其默認值為1。`Person`具有一個可空的`residence`屬性,其類型為`Residence?`。 如果創建一個新的`Person`實例,因為它的`residence`屬性是可空的,`john`屬性將初始化為`nil`: ~~~ let john = Person() ~~~ 如果使用嘆號(!)強制展開獲得這個`john`的`residence`屬性中的`numberOfRooms`值,會觸發運行時錯誤,因為這時沒有可以展開的`residence`: ~~~ let roomCount = john.residence!.numberOfRooms // this triggers a runtime error ~~~ `john.residence`非空的時候,上面的調用成功,并且把`roomCount`設置為`Int`類型的房間數量。正如上面說到的,當`residence`為空的時候上面這段代碼會觸發運行時錯誤。 可空鏈式調用提供了一種另一種訪問`numberOfRooms`的方法,使用問號(?)來代替原來嘆號(!)的位置: ~~~ if let roomCount = john.residence?.numberOfRooms { print("John's residence has \(roomCount) room(s).") } else { print("Unable to retrieve the number of rooms.") } // prints "Unable to retrieve the number of rooms." ~~~ 在`residence`后面添加問號之后,Swift就會在`residence`不為空的情況下訪問`numberOfRooms`。 因為訪問`numberOfRooms`有可能失敗,可空鏈式調用會返回`Int?`類型,或稱為“可空的Int”。如上例所示,當`residence`為`nil`的時候,可空的`Int`將會為`nil`,表明無法訪問`numberOfRooms`。 要注意的是,即使`numberOfRooms`是不可空的`Int`時,這一點也成立。只要是通過可空鏈式調用就意味著最后`numberOfRooms`返回一個`Int?`而不是`Int`。 通過賦給`john.residence`一個`Residence`的實例變量: ~~~ john.residence = Residence() ~~~ 這樣`john.residence`不為`nil`了。現在就可以正常訪問`john.residence.numberOfRooms`,其值為默認的1,類型為`Int?`: ~~~ if let roomCount = john.residence?.numberOfRooms { print("John's residence has \(roomCount) room(s).") } else { print("Unable to retrieve the number of rooms.") } // prints "John's residence has 1 room(s)." ~~~ ## 為可空鏈式調用定義模型類 通過使用可空鏈式調用可以調用多層屬性,方法,和下標。這樣可以通過各種模型向下訪問各種子屬性。并且判斷能否訪問子屬性的屬性,方法或下標。 下面這段代碼定義了四個模型類,這些例子包括多層可空鏈式調用。為了方便說明,在`Person`和`Residence`的基礎上增加了`Room`和`Address`,以及相關的屬性,方法以及下標。 Person類定義基本保持不變: ~~~ class Person { var residence: Residence? } ~~~ `Residence`類比之前復雜些,增加了一個`Room`類型的空數組`room`: ~~~ class Residence { var rooms = [Room]() var numberOfRooms: Int { return rooms.count } subscript(i: Int) -> Room { get { return rooms[i] } set { rooms[i] = newValue } } func printNumberOfRooms() { print("The number of rooms is \(numberOfRooms)") } var address: Address? } ~~~ 現在`Residence`有了一個存儲`Room`類型的數組,`numberOfRooms`屬性需要計算,而不是作為單純的變量。計算后的`numberOfRooms`返回`rooms`數組的`count`屬性值。現在的`Residence`還提供訪問`rooms`數組的快捷方式, 通過可讀寫的下標來訪問指定位置的數組元素。此外,還提供`printNumberOfRooms`方法,這個方法的作用就是輸出這個房子中房間的數量。最后,`Residence`定義了一個可空屬性`address`,其類型為`Address?`。`Address`類的定義在下面會說明。 類`Room`是一個簡單類,只包含一個屬性`name`,以及一個初始化函數: ~~~ class Room { let name: String init(name: String) { self.name = name } } ~~~ 最后一個類是`Address`,這個類有三個`String?`類型的可空屬性。`buildingName`以及`buildingNumber`屬性表示建筑的名稱和號碼,用來表示某個特定的建筑。第三個屬性表示建筑所在街道的名稱: ~~~ class Address { var buildingName: String? var buildingNumber: String? var street: String? func buildingIdentifier() -> String? { if buildingName != nil { return buildingName } else if buildingNumber != nil { return buildingNumber } else { return nil } } } ~~~ 類`Address`提供`buildingIdentifier()`方法,返回值為`String?`。 如果`buildingName`不為空則返回`buildingName`, 如果`buildingNumber`不為空則返回`buildingNumber`。如果這兩個屬性都為空則返回`nil`。 ## 通過可空鏈式調用訪問屬性 正如[使用可空鏈式調用來強制展開](http://wiki.jikexueyuan.com/project/swift/chapter2/17_Optional_Chaining.html#optional_chaining_as_an_alternative_to_forced_unwrapping)中所述,可以通過可空鏈式調用訪問屬性的可空值,并且判斷訪問是否成功。 下面的代碼創建了一個`Person`實例,然后訪問`numberOfRooms`屬性: ~~~ let john = Person() if let roomCount = john.residence?.numberOfRooms { print("John's residence has \(roomCount) room(s).") } else { print("Unable to retrieve the number of rooms.") } // prints "Unable to retrieve the number of rooms." ~~~ 因為`john.residence`為`nil`,所以毫無疑問這個可空鏈式調用失敗。 通過可空鏈式調用來設定屬性值: ~~~ let someAddress = Address() someAddress.buildingNumber = "29" someAddress.street = "Acacia Road" john.residence?.address = someAddress ~~~ 在這個例子中,通過`john.residence`來設定`address`屬性也是不行的,因為`john.residence`為`nil`。 ## 通過可空鏈式調用來調用方法 可以通過可空鏈式調用來調用方法,并判斷是否調用成功,即使這個方法沒有返回值。?`Residence`中的`printNumberOfRooms()`方法輸出當前的`numberOfRooms`值: ~~~ func printNumberOfRooms() { print("The number of rooms is \(numberOfRooms)") } ~~~ 這個方法沒有返回值。但是沒有返回值的方法隱式返回`Void`類型,如[無返回值函數](http://wiki.jikexueyuan.com/project/swift/chapter2/06_Functions.html#functions_without_return_values)中所述。這意味著沒有返回值的方法也會返回()或者空的元組。 如果在可空值上通過可空鏈式調用來調用這個方法,這個方法的返回類型為`Void?`,而不是`Void`,因為通過可空鏈式調用得到的返回值都是可空的。這樣我們就可以使用`if`語句來判斷能否成功調用`printNumberOfRooms()`方法,即使方法本身沒有定義返回值。通過返回值是否為`nil`可以判斷調用是否成功: ~~~ if john.residence?.printNumberOfRooms() != nil { print("It was possible to print the number of rooms.") } else { print("It was not possible to print the number of rooms.") } // prints "It was not possible to print the number of rooms." ~~~ 同樣的,可以判斷通過可空鏈式調用來給屬性賦值是否成功。在上面的例子中,我們嘗試給`john.residence`中的`address`屬性賦值,即使`residence`為`nil`。通過可空鏈式調用給屬性賦值會返回`Void?`,通過判斷返回值是否為`nil`可以知道賦值是否成功: ~~~ if (john.residence?.address = someAddress) != nil { print("It was possible to set the address.") } else { print("It was not possible to set the address.") } // prints "It was not possible to set the address." ~~~ ## 通過可空鏈式調用來訪問下標 通過可空鏈式調用,我們可以用下標來對可空值進行讀取或寫入,并且判斷下標調用是否成功。 > 注意: 當通過可空鏈式調用訪問可空值的下標的時候,應該將問號放在下標方括號的前面而不是后面。可空鏈式調用的問號一般直接跟在可空表達式的后面。 下面這個例子用下標訪問`john.residence`中`rooms`數組中第一個房間的名稱,因為`john.residence`為`nil`,所以下標調用毫無疑問失敗了: ~~~ if let firstRoomName = john.residence?[0].name { print("The first room name is \(firstRoomName).") } else { print("Unable to retrieve the first room name.") } // prints "Unable to retrieve the first room name." ~~~ 在這個例子中,問號直接放在`john.residence`的后面,并且在方括號的前面,因為`john.residence`是可空值。 類似的,可以通過下標,用可空鏈式調用來賦值: ~~~ john.residence?[0] = Room(name: "Bathroom") ~~~ 這次賦值同樣會失敗,因為`residence`目前是`nil`。 如果你創建一個`Residence`實例,添加一些`Room`實例并賦值給`john.residence`,那就可以通過可選鏈和下標來訪問數組中的元素: ~~~ let johnsHouse = Residence() johnsHouse.rooms.append(Room(name: "Living Room")) johnsHouse.rooms.append(Room(name: "Kitchen")) john.residence = johnsHouse if let firstRoomName = john.residence?[0].name { print("The first room name is \(firstRoomName).") } else { print("Unable to retrieve the first room name.") } // prints "The first room name is Living Room." ~~~ ## 訪問可空類型的下標: 如果下標返回可空類型值,比如Swift中`Dictionary`的`key`下標。可以在下標的閉合括號后面放一個問號來鏈接下標的可空返回值: ~~~ var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]] testScores["Dave"]?[0] = 91 testScores["Bev"]?[0]++ testScores["Brian"]?[0] = 72 // the "Dave" array is now [91, 82, 84] and the "Bev" array is now [80, 94, 81] ~~~ 上面的例子中定義了一個`testScores`數組,包含了兩個鍵值對, 把`String`類型的`key`映射到一個整形數組。這個例子用可空鏈式調用把“Dave”數組中第一個元素設為91,把”Bev”數組的第一個元素+1,然后嘗試把”Brian”數組中的第一個元素設為72。前兩個調用是成功的,因為這兩個`key`存在。但是key“Brian”在字典中不存在,所以第三個調用失敗。 ## 多層鏈接 可以通過多個鏈接多個可空鏈式調用來向下訪問屬性,方法以及下標。但是多層可空鏈式調用不會添加返回值的可空性。 也就是說: * 如果你訪問的值不是可空的,通過可空鏈式調用將會放回可空值。 * 如果你訪問的值已經是可空的,通過可空鏈式調用不會變得“更”可空。 因此: * 通過可空鏈式調用訪問一個`Int`值,將會返回`Int?`,不過進行了多少次可空鏈式調用。 * 類似的,通過可空鏈式調用訪問`Int?`值,并不會變得更加可空。 下面的例子訪問`john`中的`residence`中的`address`中的`street`屬性。這里使用了兩層可空鏈式調用,`residence`以及`address`,這兩個都是可空值。 ~~~ if let johnsStreet = john.residence?.address?.street { print("John's street name is \(johnsStreet).") } else { print("Unable to retrieve the address.") } // prints "Unable to retrieve the address." ~~~ `john.residence`包含`Residence`實例,但是`john.residence.address`為`nil`。因此,不能訪問`john.residence?.address?.street`。 需要注意的是,上面的例子中,`street`的屬性為`String?`。`john.residence?.address?.street`的返回值也依然是`String?`,即使已經進行了兩次可空的鏈式調用。 如果把`john.residence.address`指向一個實例,并且為`address`中的`street`屬性賦值,我們就能過通過可空鏈式調用來訪問`street`屬性。 ~~~ let johnsAddress = Address() johnsAddress.buildingName = "The Larches" johnsAddress.street = "Laurel Street" john.residence?.address = johnsAddress if let johnsStreet = john.residence?.address?.street { print("John's street name is \(johnsStreet).") } else { print("Unable to retrieve the address.") } // prints "John's street name is Laurel Street." ~~~ 在上面的例子中,因為`john.residence`是一個可用的`Residence`實例,所以對`john.residence`的`address`屬性賦值成功。 ## 對返回可空值的函數進行鏈接 上面的例子說明了如何通過可空鏈式調用來獲取可空屬性值。我們還可以通過可空鏈式調用來調用返回可空值的方法,并且可以繼續對可空值進行鏈接。 在下面的例子中,通過可空鏈式調用來調用`Address`的`buildingIdentifier()`方法。這個方法返回`String?`類型。正如上面所說,通過可空鏈式調用的方法的最終返回值還是`String?`: ~~~ if let buildingIdentifier = john.residence?.address?.buildingIdentifier() { print("John's building identifier is \(buildingIdentifier).") } // prints "John's building identifier is The Larches." ~~~ 如果要進一步對方法的返回值進行可空鏈式調用,在方法`buildingIdentifier()`的圓括號后面加上問號: ~~~ if let beginsWithThe = john.residence?.address?.buildingIdentifier()?.hasPrefix("The") { if beginsWithThe { print("John's building identifier begins with \"The\".") } else { print("John's building identifier does not begin with \"The\".") } } // prints "John's building identifier begins with "The"." ~~~ > 注意: 在上面的例子中在,在方法的圓括號后面加上問號是因為`buildingIdentifier()`的返回值是可空值,而不是方法本身是可空的。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看