初探swift語言的學習筆記二(可選類型?和隱式可選類型!)


做者: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

[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. enum Optional<T> : LogicValue, Reflectable {  
  2.     case None  
  3.     case Some(T)  
  4.     init()  
  5.     init(_ some: T)  
  6.   
  7.     /// Allow use in a Boolean context.  
  8.     func getLogicValue() -> Bool  
  9.   
  10.     /// Haskell's fmap, which was mis-named  
  11.     func map<U>(f: (T) -> U) -> U?  
  12.     func getMirror() -> Mirror  
  13. }  


語法使用「?」操做符及"!"號操做符 學習

如:「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

[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. var optional :String? = "ok good";//注意?與=號之間有空格?號緊貼最後一個字母不能有空格  
  2. println(optional)  

輸出爲: .net

ok good 翻譯

[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. var optional :String?//注意?與=號之間有空格?號緊貼最後一個字母不能有空格  
  2. println(optional)  

輸出爲:

nil 指針


來看下!號,官方釋爲隱式解包:主要用在一個變量/常量在定義瞬間完成以後值必定會存在的狀況。這主要用在類的初始化過程當中。 code

官風例子:

[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. let possibleString: String? = "An optional string."  
  2. println(possibleString!) // requires an exclamation mark to access its value  
  3. // prints "An optional string."  
  4.   
  5. let assumedString: String! = "An implicitly unwrapped optional string."  
  6. println(assumedString) // no exclamation mark is needed to access its value  

實說話,你照這個例子運行,還真看不出什麼,得不出什麼結論。所以我本身Z磨着,試着理解一個英文翻譯。再本身操刀練習。得出下面的一些結論。

[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. var optionVariables:String? //?至關於下面這種寫法的語法糖  
  2. //var optionVariables : Optional<Int>  
  3. let value = optionVariables?.hashValue  
  4. /* 
  5. optionVariables是可選類型的字符串,若是optionVariables是nil,則hashValue也爲nil 
  6. 若是optionVariables不爲nil,hashValue就是strValue字符串的哈希值 
  7. 到這裏咱們看到了?的兩種使用場景: 
  8. 1.聲明Optional值變量 
  9. 2.用在對Optional值操做中,用來判斷是否能響應後面的操做 
  10. */  
  11.   
  12. //對於可選類型變量,不能直接進行操做,不然會報錯  
  13. //let hashval = optionVariables.hashValue //'String?' does not have a member named 'hashValue'  
  14. //所以要訪問值就須要解包,解包有兩種  
  15. //第一種:使用if let/var xxx =   
  16. if let hv = optionVariables  
  17. {  
  18.     //run ok;  
  19. }  
  20.   
  21. //第二種:使用!號  
  22. let hv = optionVariables!.hashValue  
  23.   
  24. //這裏的!表示「我肯定這裏的的strValue必定是非nil的,盡情調用吧」 ,好比這種狀況:  
  25.   
  26. if optionVariables {  
  27.     let hashv = optionVariables!.hashValue  
  28. }  
  29. //{}裏的optionVariables必定是非nil的,因此就能直接加上!,強制拆包(unwrap)並執行後面的操做  


凡在變量或常量後加上?的都是一個可選變量/可選常量
凡在變量或常量後加上!的都是隱式可選變量/常量,有點難理解,首先該變量或常量知足可選類型,其主要是可被當生通常的變量/常量來使用,而不須要每次都驗證是否有值。

注:若是一個隱式解包的可選類型不包含一個實際值,那麼對它的訪問會拋出一個運行時錯誤。在變量/常量名後面加!的狀況也是同樣的。

[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. var possibleString: String? = "An optional string."  
  2. //possibleString = nil  
  3. println(possibleString) // possibleString 爲可選變量,須要使用!來訪問的值  
分析:首先 possibleString 因後面帶上了?說明這是一個可選的,同時前面加上var爲變量,因此這是一個可選類型的變量。其可選值爲 "An optional string." 再來看執行println後,能夠看出輸出爲 An optional string. 這點很明顯。再來看一下把println這句改一下改成 (即在可選變量後面加上一個!號。)
[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. <span style="font-size:18px;">println(possibleString!) // possibleString 爲可選變量,須要使用!來訪問的值</span>  
這裏結果與沒有加!號時是徹底同樣的,輸出爲An optional string. 

好,如今重點來了,這是很關鍵的一個測試。把possibleString = nil 這句註釋放開讓其動行,再分別來看一下println帶!和不帶!的狀況:

狀況一:不帶!號時,輸出爲nil .

[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. <span style="font-size:18px;">        var possibleString: String? = "An optional string."  
  2.         possibleString = nil  
  3.         println(possibleString) </span>  
狀況二:再來看一下帶!號
[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. <span style="font-size:18px;">        var possibleString: String? = "An optional string."  
  2.         possibleString = nil  
  3.         println(possibleString!) // possibleString 爲可選變量,須要使用!來訪問的值</span>  
這時運行到這句println就會crash了。會報

fatal error: Can't unwrap Optional.None

錯誤。 

在狀況一時,爲何不會報錯,是由於這是一個可選變量當變量爲nil時,自動驗證是否有可選的值,有則使用可選值,在狀況二,加上!訪問符來訪問possibleString 變量,但因爲possibleString設爲了nil (等價於var possibleString: String?) 其並無包含一個實際值,因此拋異常.一樣對於下面使用!號來聲明的也同樣道:

[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. <span style="font-size:18px;">        var assumedString: String! = "An implicitly unwrapped optional string."  
  2.         assumedString = nil  
  3.         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

至於何時使用?什麼狀況下使用!號來約束變量,我尚未悟出真真原理。

所以藉助於本身的幾回驗證來幫助你們理解。

[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. <span style="font-size:18px;">        var btn  :UIButton?      // 默認btn = nil  
  2.         var btn2 :UIButton = UIButton()    // 默認實例化一個對對象  
  3.         var btn3 :UIButton!     // 默認btn = nil  
  4.         //var btn4 :UIButton    //編譯期報錯 要求進行初始化操做  
  5.         //運行會報錯fatal error: Can't unwrap Optional.None 因btn = nil  
  6.         btn!.tintColor = UIColor.blackColor()  
  7.         btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  8.         btn!.frame = CGRectMake(0,0,50,40)  
  9.           
  10.         //運行正常  
  11.         btn2.tintColor = UIColor.blackColor()  
  12.         btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  13.         btn2.frame = CGRectMake(0,0,50,40)  
  14.           
  15.         //運行會報錯fatal error: Can't unwrap Optional.None 因btn3 = nil  
  16.         btn3.tintColor = UIColor.blackColor()  
  17.         btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  18.         btn3.frame = CGRectMake(0,0,50,40)</span>  

所以爲了運行期不crash能夠改成以下:

[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. <span style="font-size:18px;">        var btn  :UIButton?      // 默認btn = nil  
  2.         var btn2 :UIButton = UIButton()    // 默認實例化一個對對象  
  3.         var btn3 :UIButton!     // 默認btn = nil  
  4.           
  5.         //運行會報錯fatal error: Can't unwrap Optional.None 因btn = nil  
  6.         if var tmpbtn = btn  
  7.         {  
  8.             btn!.tintColor = UIColor.blackColor()  
  9.             btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  10.             btn!.frame = CGRectMake(0,0,50,40)  
  11.         }  
  12.           
  13.         //運行正常  
  14.         btn2.tintColor = UIColor.blackColor()  
  15.         btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  16.         btn2.frame = CGRectMake(0,0,50,40)  
  17.           
  18.         //運行會報錯fatal error: Can't unwrap Optional.None 因btn3 = nil  
  19.         if var tmpbtn = btn  
  20.         {  
  21.             btn3.tintColor = UIColor.blackColor()  
  22.             btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  23.             btn3.frame = CGRectMake(0,0,50,40)  
  24.         }</span>  
或者

[cpp]  view plain  copy
  在CODE上查看代碼片 派生到個人代碼片
  1. <span style="font-size:18px;">        var btn  :UIButton?      // 默認btn = nil  
  2.         var btn2 :UIButton = UIButton()    // 默認實例化一個對對象  
  3.         var btn3 :UIButton!     // 默認btn = nil  
  4.           
  5.         //運行會報錯fatal error: Can't unwrap Optional.None 因btn = nil  
  6.         if btn  
  7.         {  
  8.             btn!.tintColor = UIColor.blackColor()  
  9.             btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  10.             btn!.frame = CGRectMake(0,0,50,40)  
  11.         }  
  12.           
  13.         //運行正常  
  14.         btn2.tintColor = UIColor.blackColor()  
  15.         btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  16.         btn2.frame = CGRectMake(0,0,50,40)  
  17.           
  18.         //運行會報錯fatal error: Can't unwrap Optional.None 因btn3 = nil  
  19.         if btn3  
  20.         {  
  21.             btn3.tintColor = UIColor.blackColor()  
  22.             btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)  
  23.             btn3.frame = CGRectMake(0,0,50,40)  
  24.         }</span>  
注:若是一個可選類型存在沒有值的可能的話,不該該使用解包(隱式)可選類型。這種狀況下,必定要使用正常的可選類型。

這句話我我的是這樣理解的,如var view:UIView。當個人整個應用中或整個類中不可能存在view = nil的狀況時能夠設置爲var view:UIView! 不然就可聲明爲var view:UIView?

相關文章
相關標籤/搜索