做者:fengsh998
原文地址:http://blog.csdn.net/fengsh998/article/details/28904115
可選類型、隱式可選類型 swift
在swift中,可選類型其根源是一個枚舉型,裏面有None和Some兩種類型。其實所謂的nil就是Optional.None, 非nil就是Optional.Some, 而後會經過Some(T)包裝(wrap)原始值,這也是爲何在使用Optional的時候要拆包(從enum裏取出來原始值)的緣由, 也是PlayGround會把Optional值顯示爲相似{Some "hello world"}的緣由,這裏是enum Optional的定義: app
- 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
- }
語法使用「?」操做符及"!"號操做符 學習
如:「var optionalString: String? = "Hello"
optionalString == nil
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}」
你們把optionalName改成nil時看一下會有什麼結果?按照理解,應該是? = 後的爲可選值,即當咱們的的變量爲nil時,這裏若是有?=操做,則會使用?=後的值做爲默認值,而不會爲nil. 這個等有環境時,驗證一下。 測試
經驗證: ui
分別執行: spa
- var optional :String? = "ok good";//注意?與=號之間有空格?號緊貼最後一個字母不能有空格
- println(optional)
輸出爲: .net
ok good 翻譯
與
- var optional :String?//注意?與=號之間有空格?號緊貼最後一個字母不能有空格
- println(optional)
輸出爲:
nil 指針
來看下!號,官方釋爲隱式解包:主要用在一個變量/常量在定義瞬間完成以後值必定會存在的狀況。這主要用在類的初始化過程當中。 code
官風例子:
- let possibleString: String? = "An optional string."
- println(possibleString!) // requires an exclamation mark to access its value
- // prints "An optional string."
-
- let assumedString: String! = "An implicitly unwrapped optional string."
- println(assumedString) // no exclamation mark is needed to access its value
實說話,你照這個例子運行,還真看不出什麼,得不出什麼結論。所以我本身Z磨着,試着理解一個英文翻譯。再本身操刀練習。得出下面的一些結論。
- var optionVariables:String? //?至關於下面這種寫法的語法糖
- //var optionVariables : Optional<Int>
- let value = optionVariables?.hashValue
- /*
- optionVariables是可選類型的字符串,若是optionVariables是nil,則hashValue也爲nil
- 若是optionVariables不爲nil,hashValue就是strValue字符串的哈希值
- 到這裏咱們看到了?的兩種使用場景:
- 1.聲明Optional值變量
- 2.用在對Optional值操做中,用來判斷是否能響應後面的操做
- */
-
- //對於可選類型變量,不能直接進行操做,不然會報錯
- //let hashval = optionVariables.hashValue //'String?' does not have a member named 'hashValue'
- //所以要訪問值就須要解包,解包有兩種
- //第一種:使用if let/var xxx =
- if let hv = optionVariables
- {
- //run ok;
- }
-
- //第二種:使用!號
- let hv = optionVariables!.hashValue
-
- //這裏的!表示「我肯定這裏的的strValue必定是非nil的,盡情調用吧」 ,好比這種狀況:
-
- if optionVariables {
- let hashv = optionVariables!.hashValue
- }
- //{}裏的optionVariables必定是非nil的,因此就能直接加上!,強制拆包(unwrap)並執行後面的操做
凡在變量或常量後加上?的都是一個可選變量/可選常量
凡在變量或常量後加上!的都是隱式可選變量/常量,有點難理解,首先該變量或常量知足可選類型,其主要是可被當生通常的變量/常量來使用,而不須要每次都驗證是否有值。
注:若是一個隱式解包的可選類型不包含一個實際值,那麼對它的訪問會拋出一個運行時錯誤。在變量/常量名後面加!的狀況也是同樣的。
- var possibleString: String? = "An optional string."
- //possibleString = nil
- println(possibleString) // possibleString 爲可選變量,須要使用!來訪問的值
分析:首先 possibleString 因後面帶上了?說明這是一個可選的,同時前面加上var爲變量,因此這是一個可選類型的變量。其可選值爲 "An optional string." 再來看執行println後,能夠看出輸出爲 An optional string. 這點很明顯。再來看一下把println這句改一下改成 (即在可選變量後面加上一個!號。)
- <span style="font-size:18px;">println(possibleString!) // possibleString 爲可選變量,須要使用!來訪問的值</span>
這裏結果與沒有加!號時是徹底同樣的,輸出爲An optional string.
好,如今重點來了,這是很關鍵的一個測試。把possibleString = nil 這句註釋放開讓其動行,再分別來看一下println帶!和不帶!的狀況:
狀況一:不帶!號時,輸出爲nil .
- <span style="font-size:18px;"> var possibleString: String? = "An optional string."
- possibleString = nil
- println(possibleString) </span>
狀況二:再來看一下帶!號
- <span style="font-size:18px;"> var possibleString: String? = "An optional string."
- possibleString = nil
- println(possibleString!) // possibleString 爲可選變量,須要使用!來訪問的值</span>
這時運行到這句println就會crash了。會報
fatal error: Can't unwrap Optional.None
錯誤。
在狀況一時,爲何不會報錯,是由於這是一個可選變量當變量爲nil時,自動驗證是否有可選的值,有則使用可選值,在狀況二,加上!訪問符來訪問possibleString 變量,但因爲possibleString設爲了nil (等價於var possibleString: String?) 其並無包含一個實際值,因此拋異常.一樣對於下面使用!號來聲明的也同樣道:
- <span style="font-size:18px;"> var assumedString: String! = "An implicitly unwrapped optional string."
- assumedString = nil
- println(assumedString!)</span>
一樣會報:fatal error: Can't unwrap Optional.None
若是你定義了一個可選類型而且沒有給予初始值的時候,會默認設置爲nil
var surveyAnswer: String? // 初自動設置爲nil
注: Swift 的nil不一樣於Object-C中的nil. Object-C中,nil是一個指針指向不存在的對象。Swift中,nil不是指針而是一個特定類型的空值。任何類型的可選變量均可以被設爲nil,不光是指針。
在swift中做何變量/常量的聲明都必須帶有初始值,不然就要聲明爲可選型。
即var btn:UIButton 這樣是編譯報錯的。因些必須改成帶初始化的如:
var btn2 :UIButton = UIButton()
或者使用? 和! 來約束。
所以經常聲明可選或隱式可選變量如:
var btn :UIButton? // 默認btn = nil
var edt :UITextField! // 默認edt = nil
至於何時使用?什麼狀況下使用!號來約束變量,我尚未悟出真真原理。
所以藉助於本身的幾回驗證來幫助你們理解。
- <span style="font-size:18px;"> var btn :UIButton? // 默認btn = nil
- var btn2 :UIButton = UIButton() // 默認實例化一個對對象
- var btn3 :UIButton! // 默認btn = nil
- //var btn4 :UIButton //編譯期報錯 要求進行初始化操做
- //運行會報錯fatal error: Can't unwrap Optional.None 因btn = nil
- btn!.tintColor = UIColor.blackColor()
- btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn!.frame = CGRectMake(0,0,50,40)
-
- //運行正常
- btn2.tintColor = UIColor.blackColor()
- btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn2.frame = CGRectMake(0,0,50,40)
-
- //運行會報錯fatal error: Can't unwrap Optional.None 因btn3 = nil
- btn3.tintColor = UIColor.blackColor()
- btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn3.frame = CGRectMake(0,0,50,40)</span>
所以爲了運行期不crash能夠改成以下:
- <span style="font-size:18px;"> var btn :UIButton? // 默認btn = nil
- var btn2 :UIButton = UIButton() // 默認實例化一個對對象
- var btn3 :UIButton! // 默認btn = nil
-
- //運行會報錯fatal error: Can't unwrap Optional.None 因btn = nil
- if var tmpbtn = btn
- {
- btn!.tintColor = UIColor.blackColor()
- btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn!.frame = CGRectMake(0,0,50,40)
- }
-
- //運行正常
- btn2.tintColor = UIColor.blackColor()
- btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn2.frame = CGRectMake(0,0,50,40)
-
- //運行會報錯fatal error: Can't unwrap Optional.None 因btn3 = nil
- if var tmpbtn = btn
- {
- btn3.tintColor = UIColor.blackColor()
- btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn3.frame = CGRectMake(0,0,50,40)
- }</span>
或者
- <span style="font-size:18px;"> var btn :UIButton? // 默認btn = nil
- var btn2 :UIButton = UIButton() // 默認實例化一個對對象
- var btn3 :UIButton! // 默認btn = nil
-
- //運行會報錯fatal error: Can't unwrap Optional.None 因btn = nil
- if btn
- {
- btn!.tintColor = UIColor.blackColor()
- btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn!.frame = CGRectMake(0,0,50,40)
- }
-
- //運行正常
- btn2.tintColor = UIColor.blackColor()
- btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn2.frame = CGRectMake(0,0,50,40)
-
- //運行會報錯fatal error: Can't unwrap Optional.None 因btn3 = nil
- if btn3
- {
- btn3.tintColor = UIColor.blackColor()
- btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
- btn3.frame = CGRectMake(0,0,50,40)
- }</span>
注:若是一個可選類型存在沒有值的可能的話,不該該使用解包(隱式)可選類型。這種狀況下,必定要使用正常的可選類型。
這句話我我的是這樣理解的,如var view:UIView。當個人整個應用中或整個類中不可能存在view = nil的狀況時能夠設置爲var view:UIView! 不然就可聲明爲var view:UIView?