可選鏈?zhǔn)秸{(diào)用是一種可以在當(dāng)前值可能為nil
的可選值上請(qǐng)求和調(diào)用屬性匆赃、方法及下標(biāo)的方法。如果可選值有值蒜胖,那么調(diào)用就會(huì)成功消别;如果可選值是nil
,那么調(diào)用將返回nil
台谢。多個(gè)調(diào)用可以連接在一起形成一個(gè)調(diào)用鏈寻狂,如果其中任何一個(gè)節(jié)點(diǎn)為nil
,整個(gè)調(diào)用鏈都會(huì)失敗朋沮,即返回nil
蛇券。
注意
Swift 的可選鏈?zhǔn)秸{(diào)用和 Objective-C 中向nil發(fā)送消息有些相像,但是 Swift 的可選鏈?zhǔn)秸{(diào)用可以應(yīng)用于任意類(lèi)型樊拓,并且能檢查調(diào)用是否成功纠亚。
使用可選鏈?zhǔn)秸{(diào)用代替強(qiáng)制展開(kāi)
通過(guò)在想調(diào)用的屬性、方法筋夏、或下標(biāo)的可選值后面放一個(gè)問(wèn)號(hào)(?
)蒂胞,可以定義一個(gè)可選鏈。這一點(diǎn)很像在可選值后面放一個(gè)嘆號(hào)(!
)來(lái)強(qiáng)制展開(kāi)它的值条篷。它們的主要區(qū)別在于當(dāng)可選值為空時(shí)可選鏈?zhǔn)秸{(diào)用只會(huì)調(diào)用失敗骗随,然而強(qiáng)制展開(kāi)將會(huì)觸發(fā)運(yùn)行時(shí)錯(cuò)誤。
特別地赴叹,可選鏈?zhǔn)秸{(diào)用的返回結(jié)果與原本的返回結(jié)果具有相同的類(lèi)型鸿染,但是被包裝成了一個(gè)可選值。例如稚瘾,使用可選鏈?zhǔn)秸{(diào)用訪問(wèn)屬性,當(dāng)可選鏈?zhǔn)秸{(diào)用成功時(shí)姚炕,如果屬性原本的返回結(jié)果是Int
類(lèi)型摊欠,則會(huì)變?yōu)?code>Int?類(lèi)型丢烘。
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
可選鏈?zhǔn)秸{(diào)用提供了另一種訪問(wèn)numberOfRooms
的方式,使用問(wèn)號(hào)(?
)來(lái)替代原來(lái)的嘆號(hào)(!
):
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
// 打印 “Unable to retrieve the number of rooms.”
在residence
后面添加問(wèn)號(hào)之后些椒,Swift 就會(huì)在residence
不為nil
的情況下訪問(wèn)numberOfRooms
播瞳。
為可選鏈?zhǔn)秸{(diào)用定義模型類(lèi)
通過(guò)使用可選鏈?zhǔn)秸{(diào)用可以調(diào)用多層屬性、方法和下標(biāo)免糕。這樣可以在復(fù)雜的模型中向下訪問(wèn)各種子屬性赢乓,并且判斷能否訪問(wèn)子屬性的屬性、方法或下標(biāo)石窑。
class Person {
var residence: Residence?
}
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?
}
class Room {
let name: String
init(name: String) { self.name = name }
}
class Address {
var buildingName: String?
var buildingNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if buildingName != nil {
return buildingName
} else if buildingNumber != nil && street != nil {
return "\(buildingNumber) \(street)"
} else {
return nil
}
}
}
通過(guò)可選鏈?zhǔn)秸{(diào)用訪問(wèn)屬性
下面的代碼創(chuàng)建了一個(gè)Person
實(shí)例牌芋,然后像之前一樣,嘗試訪問(wèn)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.")
}
// 打印 “Unable to retrieve the number of rooms.”
通過(guò)可選鏈?zhǔn)秸{(diào)用調(diào)用方法
可以通過(guò)可選鏈?zhǔn)秸{(diào)用來(lái)調(diào)用方法松逊,并判斷是否調(diào)用成功躺屁,即使這個(gè)方法沒(méi)有返回值。
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.")
}
// 打印 “It was not possible to print the number of rooms.”
同樣的经宏,可以據(jù)此判斷通過(guò)可選鏈?zhǔn)秸{(diào)用為屬性賦值是否成功犀暑。
if (john.residence?.address = someAddress) != nil {
print("It was possible to set the address.")
} else {
print("It was not possible to set the address.")
}
// 打印 “It was not possible to set the address.”
通過(guò)可選鏈?zhǔn)秸{(diào)用訪問(wèn)下標(biāo)
通過(guò)可選鏈?zhǔn)秸{(diào)用,我們可以在一個(gè)可選值上訪問(wèn)下標(biāo)烁兰,并且判斷下標(biāo)調(diào)用是否成功耐亏。
注意
通過(guò)可選鏈?zhǔn)秸{(diào)用訪問(wèn)可選值的下標(biāo)時(shí),應(yīng)該將問(wèn)號(hào)放在下標(biāo)方括號(hào)的前面而不是后面沪斟」愠剑可選鏈?zhǔn)秸{(diào)用的問(wèn)號(hào)一般直接跟在可選表達(dá)式的后面。
if let firstRoomName = john.residence?[0].name {
print("The first room name is \(firstRoomName).")
} else {
print("Unable to retrieve the first room name.")
}
// 打印 “Unable to retrieve the first room name.”
類(lèi)似的币喧,可以通過(guò)下標(biāo)轨域,用可選鏈?zhǔn)秸{(diào)用來(lái)賦值:
john.residence?[0] = Room(name: "Bathroom")
這次賦值同樣會(huì)失敗,因?yàn)?code>residence目前是nil
杀餐。
訪問(wèn)可選類(lèi)型的下標(biāo)
如果下標(biāo)返回可選類(lèi)型值干发,比如 Swift 中Dictionary
類(lèi)型的鍵的下標(biāo),可以在下標(biāo)的結(jié)尾括號(hào)后面放一個(gè)問(wèn)號(hào)來(lái)在其可選返回值上進(jìn)行可選鏈?zhǔn)秸{(diào)用:
var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
testScores["Dave"]?[0] = 91
testScores["Bev"]?[0] += 1
testScores["Brian"]?[0] = 72
// "Dave" 數(shù)組現(xiàn)在是 [91, 82, 84]史翘,"Bev" 數(shù)組現(xiàn)在是 [80, 94, 81]
上面的例子中定義了一個(gè)testScores
數(shù)組枉长,包含了兩個(gè)鍵值對(duì),把String
類(lèi)型的鍵映射到一個(gè)Int
值的數(shù)組琼讽。這個(gè)例子用可選鏈?zhǔn)秸{(diào)用把"Dave"
數(shù)組中第一個(gè)元素設(shè)為91
必峰,把"Bev"
數(shù)組的第一個(gè)元素+1
,然后嘗試把"Brian"
數(shù)組中的第一個(gè)元素設(shè)為72
钻蹬。前兩個(gè)調(diào)用成功吼蚁,因?yàn)?code>testScores字典中包含"Dave"
和"Bev"
這兩個(gè)鍵。但是testScores
字典中沒(méi)有"Brian"
這個(gè)鍵,所以第三個(gè)調(diào)用失敗肝匆。
連接多層可選鏈?zhǔn)秸{(diào)用
可以通過(guò)連接多個(gè)可選鏈?zhǔn)秸{(diào)用在更深的模型層級(jí)中訪問(wèn)屬性粒蜈、方法以及下標(biāo)。然而旗国,多層可選鏈?zhǔn)秸{(diào)用不會(huì)增加返回值的可選層級(jí)枯怖。
也就是說(shuō):
- 如果你訪問(wèn)的值不是可選的,可選鏈?zhǔn)秸{(diào)用將會(huì)返回可選值能曾。
- 如果你訪問(wèn)的值就是可選的度硝,可選鏈?zhǔn)秸{(diào)用不會(huì)讓可選返回值變得“更可選”。
因此:
- 通過(guò)可選鏈?zhǔn)秸{(diào)用訪問(wèn)一個(gè)
Int
值寿冕,將會(huì)返回Int?
蕊程,無(wú)論使用了多少層可選鏈?zhǔn)秸{(diào)用。 - 類(lèi)似的蚂斤,通過(guò)可選鏈?zhǔn)秸{(diào)用訪問(wèn)
Int?
值存捺,依舊會(huì)返回Int?
值,并不會(huì)返回Int??
曙蒸。
if let johnsStreet = john.residence?.address?.street {
print("John's street name is \(johnsStreet).")
} else {
print("Unable to retrieve the address.")
}
// 打印 “Unable to retrieve the address.”
在方法的可選返回值上進(jìn)行可選鏈?zhǔn)秸{(diào)用
如果要在該方法的返回值上進(jìn)行可選鏈?zhǔn)秸{(diào)用捌治,在方法的圓括號(hào)后面加上問(wèn)號(hào)即可:
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\".")
}
}
// 打印 “John's building identifier begins with "The".”
注意
在上面的例子中,在方法的圓括號(hào)后面加上問(wèn)號(hào)是因?yàn)槟阋赽uildingIdentifier()方法的可選返回值上進(jìn)行可選鏈?zhǔn)秸{(diào)用纽窟,而不是方法本身肖油。