背景
寫過(guò)swift的同學(xué)都只有一個(gè)可選鏈的概念,當(dāng)我們想訪問(wèn)某個(gè)變量的屬性或者方法但是不知道到這個(gè)變量是否為空的時(shí)候,直接使用'.'運(yùn)算符訪問(wèn)屬性或者方法的話,在運(yùn)行時(shí)如果變量是nil則會(huì)崩潰,這時(shí)一個(gè)便捷的方法就是在變量后使用‘?.’的方式來(lái)訪問(wèn)。今天就是和大家一個(gè)看下這個(gè)在swift和OC混用時(shí)候的一些問(wèn)題
基礎(chǔ)
可選類型
首先來(lái)個(gè)小知識(shí)點(diǎn):大家定義可選屬性的時(shí)候會(huì)使用
var name: String?
那么可選類型還能怎么寫呢?大家使用過(guò)這樣的方式嗎?
var name: Optional<String>
這第二種方式就是標(biāo)準(zhǔn)庫(kù)中定義的命名型類型 Optional<Wrapped> 也就是可選類型。而第一種方式只是它的語(yǔ)法糖。
類型 Optional<Wrapped> 是一個(gè)枚舉,有兩個(gè)成員,none 和 some(Wrapped),用來(lái)表示可能有也可能沒(méi)有的值。任意類型都可以被顯式地聲明(或隱式地轉(zhuǎn)換)為可選類型。如果你在聲明可選變量或?qū)傩缘臅r(shí)候沒(méi)有提供初始值,它的值則會(huì)自動(dòng)賦為默認(rèn)值 nil。(有關(guān)不透明類型請(qǐng)參閱相關(guān)paper)
可選鏈
可選調(diào)用就是我們?cè)谀硞€(gè)可選值可能為空的基礎(chǔ)上去訪問(wèn)它的屬性或者方法的操作,而將多個(gè)可選調(diào)用組合起來(lái)就是可選鏈。
如果可選鏈中有一個(gè)調(diào)用失敗了,那么整體返回的就是nill,而全部成功的話,不論這個(gè)調(diào)用的屬性、方法返回的值是不是可選值,它的返回結(jié)果都是一個(gè)可選值。
var name: String? = personA?.info?.name;
案例
先看這么一個(gè)問(wèn)題,假設(shè)我們有一個(gè)OC的類定義:
@interface ClassA : NSObject
@property (nonatomic, strong) NSArray<person*> *people;
@end
當(dāng)我們有一個(gè)ClassA實(shí)例的時(shí)候,假設(shè)其people是一個(gè)nill值,那么我們?cè)趕wift中這么判斷時(shí):
guard instanceA?.people.count ?? 0 else {
return
}
會(huì)有什么問(wèn)題?當(dāng)我們運(yùn)行的時(shí)候會(huì)發(fā)生什么呢?
系統(tǒng)會(huì)提示如下錯(cuò)誤
Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
這是因?yàn)镺C中默認(rèn)的可以為nil的值在swift中就會(huì)變成nil,盡管它聲明時(shí)處于非空假設(shè)中。
而可選鏈在每個(gè)環(huán)節(jié)都應(yīng)該加‘?.’?;蛘哒f(shuō)只有加了‘?.’的表達(dá)式才稱為一個(gè)可選鏈的一部分。
如果我們?cè)L問(wèn)一個(gè)包含可選鏈的判斷語(yǔ)句的時(shí)候,只有可選鏈中的部分才會(huì)進(jìn)行為nil就返回的邏輯,比如上述代碼中第一部分
instanceA?.
這一部分的意思是如果instanceA為nil則表達(dá)式返回nil.反之則返回‘.’運(yùn)算符的結(jié)果對(duì)應(yīng)的可選值。
假設(shè)我們的第二個(gè)屬性也是空的,也就是people為nil;
instanceA?.people
代碼到這里也不會(huì)有問(wèn)題,因?yàn)椤?’在非空的實(shí)例上訪問(wèn)了一個(gè)nill值,返回的是一個(gè)nil,從而表達(dá)式整體都是一個(gè)nil的值了。也就是'''instanceA?.people '''表達(dá)式的整體值為nil。
但是,當(dāng)我們加上第三部分的時(shí)候, 也就是表達(dá)式變成:
instanceA?.people.count
這時(shí)people為nil意味著對(duì)一個(gè)nil的變量做一個(gè)屬性訪問(wèn),因?yàn)闆](méi)有'?',相當(dāng)于強(qiáng)制解包,所以才會(huì)出現(xiàn)這個(gè)問(wèn)題。
而至于之后的?? 它計(jì)算左表達(dá)式的時(shí)候就已經(jīng)崩潰了,所以沒(méi)有機(jī)會(huì)執(zhí)行了。
問(wèn)題
那么為什么當(dāng)時(shí)寫的時(shí)候沒(méi)有加‘?.’而是直接用了‘.’呢。因?yàn)槎x在OC中,而判斷在swift中,OC定義的文件默認(rèn)會(huì)有非空的宏包裹定義。swift默認(rèn)它時(shí)非空的,所以才會(huì)出現(xiàn)此問(wèn)題。
總結(jié)
可選鏈就是多個(gè)可選調(diào)用的組合,要在每一個(gè)可能為空的表達(dá)式處加上可選調(diào)用'?'才能保證不會(huì)對(duì)nil值使用‘.’運(yùn)算符。