可選類型、隱式可選類型
在swift中,可選類型其根源是一個(gè)枚舉型,里面有None和Some兩種類型。其實(shí)所謂的nil就是Optional.None, 非nil就是Optional.Some, 然后會(huì)通過Some(T)包裝(wrap)原始值,這里是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
}
語法使用“?”操作符及"!"號(hào)操作符
如:“var optionalString: String? = "Hello"
optionalString == nil
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}”
大家把optionalName改為nil時(shí)看一下會(huì)有什么結(jié)果?按照理解,應(yīng)該是? = 后的為可選值,即當(dāng)我們的的變量為nil時(shí),這里如果有?=操作,則會(huì)使用?=后的值作為默認(rèn)值,而不會(huì)為nil. 這個(gè)等有環(huán)境時(shí),驗(yàn)證一下。
經(jīng)驗(yàn)證:
分別執(zhí)行:
var optional :String? = "ok good";//注意?與=號(hào)之間有空格?號(hào)緊貼最后一個(gè)字母不能有空格
println(optional)
輸出為:
ok good
與
var optional :String?//注意?與=號(hào)之間有空格?號(hào)緊貼最后一個(gè)字母不能有空格
println(optional)
輸出為:
nil
來看下官方釋為隱式解包:主要用在一個(gè)變量/常量在定義瞬間完成之后值一定會(huì)存在的情況。這主要用在類的初始化過程中。
var optionVariables:String? //?相當(dāng)于下面這種寫法的語法糖
//var optionVariables : Optional<Int>
let value = optionVariables?.hashValue
/*
optionVariables是可選類型的字符串,如果optionVariables是nil,則hashValue也為nil
如果optionVariables不為nil,hashValue就是strValue字符串的哈希值
到這里我們看到了?的兩種使用場(chǎng)景:
1.聲明Optional值變量
2.用在對(duì)Optional值操作中,用來判斷是否能響應(yīng)后面的操作
*/
//對(duì)于可選類型變量,不能直接進(jìn)行操作,否則會(huì)報(bào)錯(cuò)
//let hashval = optionVariables.hashValue //'String?' does not have a member named 'hashValue'
//因此要訪問值就需要解包,解包有兩種
//第一種:使用if let/var xxx =
if let hv = optionVariables
{
//run ok;
}
//第二種:使用!號(hào)
let hv = optionVariables!.hashValue
//這里的!表示“我確定這里的的strValue一定是非nil的,盡情調(diào)用吧” ,比如這種情況:
if optionVariables {
let hashv = optionVariables!.hashValue
}
//{}里的optionVariables一定是非nil的,所以就能直接加上!,強(qiáng)制拆包(unwrap)并執(zhí)行后面的操作
凡在變量或常量后加上?的都是一個(gè)可選變量/可選常量
凡在變量或常量后加上!的都是隱式可選變量/常量,有點(diǎn)難理解,首先該變量或常量滿足可選類型,其主要是可被當(dāng)生一般的變量/常量來使用,而不需要每次都驗(yàn)證是否有值。
注:如果一個(gè)隱式解包的可選類型不包含一個(gè)實(shí)際值,那么對(duì)它的訪問會(huì)拋出一個(gè)運(yùn)行時(shí)錯(cuò)誤。在變量/常量名后面加!的情況也是一樣的。
var possibleString: String? = "An optional string."
//possibleString = nil
println(possibleString) // possibleString 為可選變量,需要使用!來訪問的值
分析:首先 possibleString 因后面帶上了?說明這是一個(gè)可選的,同時(shí)前面加上var為變量,所以這是一個(gè)可選類型的變量。其可選值為 "An optional string." 再來看執(zhí)行println后,可以看出輸出為 An optional string. 這點(diǎn)很明顯。再來看一下把println這句改一下改為 (即在可選變量后面加上一個(gè)!號(hào)。)
println(possibleString!) // possibleString 為可選變量,需要使用!來訪問的值
這里結(jié)果與沒有加!號(hào)時(shí)是完全一樣的,輸出為An optional string.
好,現(xiàn)在重點(diǎn)來了,這是很關(guān)鍵的一個(gè)測(cè)試。把possibleString = nil 這句注釋放開讓其動(dòng)行,再分別來看一下println帶!和不帶!的情況:
情況一:不帶!號(hào)時(shí),輸出為nil .
var possibleString: String? = "An optional string."
possibleString = nil
println(possibleString)
情況二:再來看一下帶!號(hào)
var possibleString: String? = "An optional string."
possibleString = nil
println(possibleString!) // possibleString 為可選變量,需要使用!來訪問的值
這時(shí)運(yùn)行到這句println就會(huì)crash了。會(huì)報(bào)
fatal error: Can't unwrap Optional.None
錯(cuò)誤。
在情況一時(shí),為什么不會(huì)報(bào)錯(cuò),是因?yàn)檫@是一個(gè)可選變量當(dāng)變量為nil時(shí),自動(dòng)驗(yàn)證是否有可選的值,有則使用可選值,在情況二,加上!訪問符來訪問possibleString 變量,但由于possibleString設(shè)為了nil (等價(jià)于var possibleString: String?) 其并沒有包含一個(gè)實(shí)際值,所以拋異常.同樣對(duì)于下面使用!號(hào)來聲明的也一樣
var assumedString: String! = "An implicitly unwrapped optional string."
assumedString = nil
println(assumedString!)
如果你定義了一個(gè)可選類型并且沒有給予初始值的時(shí)候,會(huì)默認(rèn)設(shè)置為nil
var surveyAnswer: String? // 初自動(dòng)設(shè)置為nil
注: Swift 的nil不同于Object-C中的nil. Object-C中,nil是一個(gè)指針指向不存在的對(duì)象。Swift中,nil不是指針而是一個(gè)特定類型的空值。任何類型的可選變量都可以被設(shè)為nil,不光是指針。
在swift中作何變量/常量的聲明都必須帶有初始值,否則就要聲明為可選型。
即var btn:UIButton 這樣是編譯報(bào)錯(cuò)的。因些必須改為帶初始化的如:
var btn2 :UIButton = UIButton()
或者使用? 和! 來約束。
因此常常聲明可選或隱式可選變量如:
var btn :UIButton? // 默認(rèn)btn = nil
var edt :UITextField! // 默認(rèn)edt = nil