Swift中 !和 ?的區(qū)別及使用
相信大家在學(xué)習(xí)和使用Swift的時(shí)候,肯定會(huì)被 ! 和 ? 搞瘋過(guò), 糾結(jié)這兩個(gè)符號(hào)到底是個(gè)什么鬼 ?鬼知道什么時(shí)候使用!,什么時(shí)候使用?
下面就說(shuō)一下! 和 ? 區(qū)別以及該怎么使用!
? 和 ! 到底是個(gè)啥
? 和 ! 其實(shí)分別是Swift語(yǔ)言中對(duì)一種可選類型( Optional) 操作的語(yǔ)法糖。 那可選類型是干什么的呢? Swift中是可以聲明一個(gè)沒(méi)有初始值的屬性, Swift中引入了可選類型(Optional)來(lái)解決這一問(wèn)題。它的定義是通過(guò)在類型生命后加加一個(gè) ? 操作符完成的。
例如: var name: String?
Optional其實(shí)是個(gè)enum,里面有None和Some兩種類型。其實(shí)所謂的nil就是Optional.None , 非nil就是Optional.Some, 然后會(huì)通過(guò)Some(T)包裝(wrap)原始值,這也是為什么在使用Optional的時(shí)候要拆包(從enum里取出來(lái)原始值)的原因。
這里是enum Optional的定義
enum Optional<T> : LogicValue, Reflectable { case None case Some(T) init() init(_ some: T) /// Allow use in a Boolean context. func getLogicValue() -> Bool /// Haskell's fmap, which was mis-named func map<U>(f: (T) -> U) -> U? func getMirror() -> Mirror }
既然這樣, 那對(duì)于 var name: String? 該怎樣去理解這句語(yǔ)法呢?
var name: String?
// 上面這個(gè)Optional的聲明,是”我聲明了一個(gè)Optional類型值,它可能包含一個(gè)String值,也可能什么都不包含”,也就是說(shuō)實(shí)際上我們聲明的是Optional類型,而不是聲明了一個(gè)String類型 。
? 和 ! 使用
一旦聲明為Optional的,如果不顯式的賦值就會(huì)有個(gè)默認(rèn)值nil。判斷一個(gè)Optional的值是否有值,可以用if來(lái)判斷:
if name {
// 有值再操作
}
怎么使用Optional值呢?文檔中也有提到說(shuō),在使用Optional值的時(shí)候需要在具體的操作,比如調(diào)用方法、屬性、下標(biāo)索引等前面需要加上一個(gè)?,如果是nil值,也就是Optional.None,會(huì)跳過(guò)后面的操作不執(zhí)行,如果有值,就是Optional.Some,可能就會(huì)拆包(unwrap),然后對(duì)拆包后的值執(zhí)行后面的操作,來(lái)保證執(zhí)行這個(gè)操作的安全性。
// 例如:
let length = name?.characters.count
PS:對(duì)于 Optional 值,不能直接進(jìn)行操作,否則會(huì)報(bào)錯(cuò)。
? 的使用場(chǎng)景:
1.聲明Optional值變量
2.用在對(duì)Optional值操作中,用來(lái)判斷是否能響應(yīng)后面的操作
3.使用 as? 向下轉(zhuǎn)型(Downcast)
上面提到Optional值需要拆包(unwrap)后才能得到原來(lái)值,然后才能對(duì)其操作,那怎么來(lái)拆包呢?
拆包有兩種方法:
可選綁定(Optional Binding)
可選綁定(Optional Binding)是一種更簡(jiǎn)單更推薦的方法來(lái)解包一個(gè)可選類型。 使用可選綁定來(lái)檢查可選類型的變量有值還是沒(méi)值。如果有值, 解包它并且將值傳遞給一個(gè)常量或者變量。
// 例子最為簡(jiǎn)單明了 var str: String? = "Hello" let greeting = "World!" if let name = str { let message = greeting + name print(message) } /** 自然語(yǔ)言解釋意思:就是如果str有值,解包它,并且將它的值賦值給name, 然后執(zhí)行下面的條件語(yǔ)句; 如果str為空, 直接跳過(guò)條件語(yǔ)句塊。 */
硬解包
硬解包即直接在可選類型后面加一個(gè)感嘆號(hào)(!)來(lái)表示它肯定有值。
var str1: String? = "Hello" let greeting = "World!" if (str1 != nil) { let message = greeting + str1! print(message) } /** 上面例子,我們只是自己知道str1肯定有值, 所以才直接硬解包了str1變量。 但是萬(wàn)一有時(shí)候我們的感覺(jué)是錯(cuò)的, 那程序在運(yùn)行時(shí)可能會(huì)出現(xiàn)嚴(yán)重的錯(cuò)誤. 所以Swift中是推薦先檢查可選類型是否有值, 然后再進(jìn)行解包的! */
錯(cuò)誤示范:
var str1:String? // str1值可能是傳過(guò)來(lái)的值或者從服務(wù)器獲取的值 let msg = "Hi" let txt = msg + str1! // runtime error /** 以上代碼在編譯階段不會(huì)報(bào)錯(cuò).因?yàn)槭褂昧擞步獍? 編譯器認(rèn)為可選類型是有值的, 所以編譯是通過(guò)的. 當(dāng)代碼運(yùn)行起來(lái)時(shí), 知名的錯(cuò)誤將會(huì)出現(xiàn): `fatal error: Can't unwrap Optional.None` *
PS:對(duì)于 ! 操作符,這里的變量值一定是非nil的!
其實(shí), 還有一種叫隱式拆包(Implicitly Unwrapped Optionals),比如 對(duì)于會(huì)在viewDidLoad進(jìn)行初始化的變量,可以直接定義為var str :String! 等于說(shuō)你每次對(duì)這種類型的值操作時(shí),都會(huì)自動(dòng)在操作前補(bǔ)上一個(gè)!進(jìn)行拆包,然后在執(zhí)行后面的操作,當(dāng)然如果該值是nil,會(huì)報(bào)錯(cuò)crash掉。
舉個(gè)很淺顯的栗子:
// 在一個(gè)viewController里面,從xib里面拖一個(gè)UIImageView控件, 你會(huì)發(fā)現(xiàn)Xcode會(huì)自動(dòng)給你轉(zhuǎn)成下面的形式 @IBOutlet weak var headerBGImageView: UIImageView! /** 聲明Implicitly Unwrapped Optionals值,一般用于類中的屬性 */
PS:如果你在隱式解析可選類型沒(méi)有值的時(shí)候進(jìn)行取值,會(huì)crash。和在沒(méi)有值的可選類型里面拆包是一樣的。
! 的使用場(chǎng)景
1.強(qiáng)制對(duì)Optional值進(jìn)行拆包(unwrap)
2.聲明隱式拆包變量,一般用于類中的屬性
結(jié)束
其實(shí)! 和 ? 的問(wèn)題是很坑的,不要看它僅僅是兩個(gè)符號(hào),因?yàn)橹灰幸粋€(gè)不小心,不注意,你會(huì)發(fā)現(xiàn)項(xiàng)目運(yùn)行起來(lái),會(huì)莫名的crash掉了,關(guān)鍵是Debug模式也不是很方便定位錯(cuò)誤類型。 自己整理一下關(guān)于 可選類型的相關(guān)使用,一是記錄和鞏固所學(xué),而是希望會(huì)對(duì)大家有所幫助。 本文可能會(huì)有錯(cuò)誤和不妥之處,還望提出,我會(huì)及時(shí)改正。
相關(guān)文章
Swift解決UITableView空數(shù)據(jù)視圖問(wèn)題的簡(jiǎn)單方法
這篇文章主要給大家介紹了關(guān)于Swift解決UITableView空數(shù)據(jù)視圖問(wèn)題的簡(jiǎn)單方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用swift具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2018-10-10在Swift中使用Objective-C編寫類、繼承Objective-C類
這篇文章主要介紹了在Swift中使用Objective-C編寫類、繼承Objective-C類等操作方法介紹,需要的朋友可以參考下2014-07-07iOS Swift讀取本地json文件報(bào)錯(cuò)的解決方法
只要是app開發(fā)者都知道,從服務(wù)器端獲得的數(shù)據(jù)要不就是json格式的數(shù)據(jù),要么就是xml格式的數(shù)據(jù),而這篇文章主要給大家介紹了關(guān)于iOS Swift讀取本地json文件報(bào)錯(cuò)的解決方法,需要的朋友可以參考借鑒,下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11蘋果公司編程語(yǔ)言Swift語(yǔ)言簡(jiǎn)介
這篇文章主要介紹了蘋果公司編程語(yǔ)言Swift語(yǔ)言簡(jiǎn)介,Swift 是一門新的編程語(yǔ)言,兼容Objective-C代碼,是用來(lái)代替Objective-C的蘋果主力開發(fā)語(yǔ)言,需要的朋友可以參考下2014-07-07Swift 3.0基礎(chǔ)學(xué)習(xí)之?dāng)U展
擴(kuò)展是向一個(gè)已有的類、結(jié)構(gòu)體或枚舉類型添加新的功能(在swift中擴(kuò)展沒(méi)有名字)。相當(dāng)于Objective-C中Category(OC中可以有名字的,而且只能擴(kuò)展類)。這篇文章主要介紹了Swift 3.0基礎(chǔ)學(xué)習(xí)之?dāng)U展的相關(guān)資料,需要的朋友可以參考下。2017-03-03Swift如何為網(wǎng)頁(yè)承載頁(yè)面添加更多功能詳解
這篇文章主要給大家介紹了關(guān)于Swift如何為網(wǎng)頁(yè)承載頁(yè)面添加更多功能的相關(guān)資料,包括添加菊花加載的效果、添加跳轉(zhuǎn)到Safari的功能、添加復(fù)制鏈接的功能以及添加分享網(wǎng)頁(yè)的功能,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-05-05SwiftUI 中創(chuàng)建反彈動(dòng)畫的實(shí)現(xiàn)
這篇文章主要介紹了SwiftUI 中創(chuàng)建反彈動(dòng)畫的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10