OneDayOneSwift[17] - Optional Chaining

可選鏈?zhǔn)秸{(diào)用(Optional Chaining)是一種可以在當(dāng)前值可能為nil的可選值上請求和調(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才沧。

使用可選鏈?zhǔn)秸{(diào)用代替強(qiáng)制展開

通過在想調(diào)用的屬性、方法绍刮、或下標(biāo)的可選值(optional value)后面放一個(gè)問號(hào)(?)温圆,可以定義一個(gè)可選鏈。這一點(diǎn)很像在可選值后面放一個(gè)嘆號(hào)(!)來強(qiáng)制展開它的值孩革。它們的主要區(qū)別在于當(dāng)可選值為空時(shí)可選鏈?zhǔn)秸{(diào)用只會(huì)調(diào)用失敗岁歉,然而強(qiáng)制展開將會(huì)觸發(fā)運(yùn)行時(shí)錯(cuò)誤。

為了反映可選鏈?zhǔn)秸{(diào)用可以在空值(nil)上調(diào)用的事實(shí)膝蜈,不論這個(gè)調(diào)用的屬性锅移、方法及下標(biāo)返回的值是不是可選值,它的返回結(jié)果都是一個(gè)可選值饱搏。你可以利用這個(gè)返回值來判斷你的可選鏈?zhǔn)秸{(diào)用是否調(diào)用成功非剃,如果調(diào)用有返回值則說明調(diào)用成功,返回nil則說明調(diào)用失敗推沸。

通過可選鏈?zhǔn)秸{(diào)用訪問屬性

let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
john.residence?.address = someAddress

在這個(gè)例子中努潘,通過john.residence來設(shè)定address屬性也會(huì)失敗,因?yàn)?code>john.residence當(dāng)前為nil坤学。

上面代碼中的賦值過程是可選鏈?zhǔn)秸{(diào)用的一部分疯坤,這意味著可選鏈?zhǔn)秸{(diào)用失敗時(shí),等號(hào)右側(cè)的代碼不會(huì)被執(zhí)行深浮。對于上面的代碼來說压怠,很難驗(yàn)證這一點(diǎn),因?yàn)橄襁@樣賦值一個(gè)常量沒有任何副作用飞苇。下面的代碼完成了同樣的事情菌瘫,但是它使用一個(gè)函數(shù)來創(chuàng)建Address實(shí)例,然后將該實(shí)例返回用于賦值布卡。該函數(shù)會(huì)在返回前打印“Function was called”雨让,這使你能驗(yàn)證等號(hào)右側(cè)的代碼是否被執(zhí)行。

func createAddress() -> Address {
    print("Function was called.")

    let someAddress = Address()
    someAddress.buildingNumber = "29"
    someAddress.street = "Acacia Road"

    return someAddress
}
john.residence?.address = createAddress()

沒有任何打印消息忿等,可以看出createAddress()函數(shù)并未被執(zhí)行栖忠。
在可選鏈?zhǔn)秸{(diào)用的過程中,一旦失敗,后面的代碼都不會(huì)被執(zhí)行

通過可選鏈?zhǔn)秸{(diào)用調(diào)用方法

沒有返回值的方法具有隱式的返回類型Void,如果在可選值上通過可選鏈?zhǔn)秸{(diào)用來調(diào)用這個(gè)方法庵寞,該方法的返回類型會(huì)是Void?狸相,而不是Void,因?yàn)橥ㄟ^可選鏈?zhǔn)秸{(diào)用得到的返回值都是可選的捐川。這樣我們就可以使用if語句來判斷能否成功調(diào)用方法脓鹃。即使方法本身沒有定義返回值。

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.”

通過可選鏈?zhǔn)秸{(diào)用訪問下標(biāo)

ps: 通過可選鏈?zhǔn)秸{(diào)用訪問可選值的下標(biāo)時(shí)古沥,應(yīng)該將問號(hào)放在下標(biāo)方括號(hào)的前面而不是后面瘸右。可選鏈?zhǔn)秸{(diào)用的問號(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.”

類似的尊浓,可以通過下標(biāo),用可選鏈?zhǔn)秸{(diào)用來賦值:

john.residence?[0] = Room(name: "Bathroom")

這次賦值同樣會(huì)失敗纯衍,因?yàn)?code>residence目前是nil栋齿。

訪問可選類型的下標(biāo)

如果下標(biāo)返回可選類型值,比如 Swift 中Dictionary類型的鍵的下標(biāo)襟诸,可以在下標(biāo)的結(jié)尾括號(hào)后面放一個(gè)問號(hào)來在其可選返回值上進(jìn)行可選鏈?zhǔn)秸{(diào)用:

var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
testScores["Dave"]?[0] = 91
testScores["Bev"]?[0]++
testScores["Brian"]?[0] = 72
// "Dave" 數(shù)組現(xiàn)在是 [91, 82, 84]瓦堵,"Bev" 數(shù)組現(xiàn)在是 [80, 94, 81]

連接多層可選鏈?zhǔn)秸{(diào)用

可以通過連接多個(gè)可選鏈?zhǔn)秸{(diào)用在更深的模型層級(jí)中訪問屬性、方法以及下標(biāo)歌亲。然而菇用,多層可選鏈?zhǔn)秸{(diào)用不會(huì)增加返回值的可選層級(jí)。

也就是說:

  • 如果你訪問的值不是可選的陷揪,可選鏈?zhǔn)秸{(diào)用將會(huì)返回可選值惋鸥。
  • 如果你訪問的值就是可選的,可選鏈?zhǔn)秸{(diào)用不會(huì)讓可選返回值變得“更可選”悍缠。

因此:

  • 通過可選鏈?zhǔn)秸{(diào)用訪問一個(gè)Int值卦绣,將會(huì)返回Int?,無論使用了多少層可選鏈?zhǔn)秸{(diào)用飞蚓。
  • 類似的滤港,通過可選鏈?zhǔn)秸{(diào)用訪問Int?值,依舊會(huì)返回Int?值趴拧,并不會(huì)返回Int??溅漾。

要點(diǎn)總結(jié)

可選鏈?zhǔn)秸{(diào)用的過程中,一旦失敗則后續(xù)的代碼都不會(huì)執(zhí)行著榴。也就是說添履,在這種情況下,去調(diào)用一個(gè)nil的對方的方法是不會(huì)崩潰的脑又。
另外一點(diǎn)暮胧。返回值為void的函數(shù)锐借,返回的是()?。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞎饲,一起剝皮案震驚了整個(gè)濱河市炼绘,隨后出現(xiàn)的幾起案子妄田,更是在濱河造成了極大的恐慌,老刑警劉巖疟呐,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件启具,死亡現(xiàn)場離奇詭異,居然都是意外死亡拷沸,警方通過查閱死者的電腦和手機(jī)薯演,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來序无,“玉大人衡创,你說我怎么就攤上這事×猓” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵碗降,是天一觀的道長塘秦。 經(jīng)常有香客問我,道長尊剔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任挨稿,我火速辦了婚禮,結(jié)果婚禮上篷店,老公的妹妹穿的比我還像新娘臭家。我一直安慰自己,他們只是感情好钉赁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布你踩。 她就那樣靜靜地躺著,像睡著了一般带膜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逮京,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天束莫,我揣著相機(jī)與錄音,去河邊找鬼策严。 笑死饿敲,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的怀各。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼寿酌,長吁一口氣:“原來是場噩夢啊……” “哼硕蛹!你這毒婦竟也來了硕并?” 一聲冷哼從身側(cè)響起秧荆,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤乙濒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后琉兜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毙玻,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桑滩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了幌氮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胁澳。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖宇智,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情随橘,我是刑警寧澤锦庸,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站萝嘁,受9級(jí)特大地震影響扬卷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜邀泉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望庞钢。 院中可真熱鬧,春花似錦颜懊、人聲如沸风皿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽魔眨。三九已至,卻和暖如春遏暴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背州丹。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國打工墓毒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盖灸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓赁炎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親徙垫。 傳聞我的和親對象是個(gè)殘疾皇子姻报,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容