0000_0000_0000_0100.Optional 可選類型閒談

0000 0000 0000 0100

寫於2015.04.07 10:13

清明已過,是時候收收心,繼續碼代碼了。

Optional 可選類型閒談

在我印象中,可選類型應該分爲顯示可選類型和隱式可選類型。分別是這樣的:

var explicitPara:Type?  //顯示  初始化時假如不給賦值 默認都是nil
var implicitPara:Type!  //隱式

不知道自己記得對不對。兩者都是可選類型,自然就有共性,可選類型定義爲一個變量(不僅僅是class)要麼有值,且值等於x,要麼就不存在(nil)。

注:與oc中nil是一個指針指向不存在的對象不同,swift中,nil可不是一個指針,而是一個特定類型的空值。任何類型的可選變量都可以設爲nil,通俗理解就是不僅僅是class類型可以=nil, string ,int ,char都可以不存在=nil。這樣使得編程時候更爲安全。

昨天我還對顯示可選類型和隱式可選類型之間的差異詢問了羣裏的朋友,以及再次翻閱了The Swift programming Language

可選類型總覺得就是把值放進一個叫做Optional的盒子中。可選類型是一個枚舉,聲明是這樣的:

enum Optional<T>:Reflectable,NilLiteralConvertibel{
    case None
    case Some(T)

    /// 構建一個 a `nil` instance.
    init()

    /// 構建一個 a non-\ `nil` instance that stores `some`.
    init(_ some: T)

    /// If `self == nil`, returns `nil`.  Otherwise, returns `f(self!)`.
    func map<U>(f: (T) -> U) -> U?

    /// Returns a mirror that reflects `self`.
    func getMirror() -> MirrorType

    /// Create an instance initialized with `nil`.
    init(nilLiteral: ())

}

可見兩種情況 None 以及 Some(T), 對於T,只不過是一個泛型,指代傳入的類型(傳入Int,T就是Int ;傳入String,T就是String;傳入類,T就是特定class)。這個還是有點意思的。

繼續上面,既然把值放入了盒子中,自然取出來就是要有一個解包(unwrap)的行爲,swift是用!表示該行爲。方便記憶,舉個例子:

var str:String? = "hello world"     //把值放入盒子中包裹起來了

/*
    輸出Optional("hello world") 連帶外面那層盒子也打印出來了
    其中"hello world" 存儲到了 some 中
*/
println(str)                        

println(str!)                       //輸出“hello world” . 解包取出值  盒子已經丟棄

解包就是這麼一個形式,上面是一個顯示的可選類型,當然解包方式還包括if-let可選綁定,??等。

顯示可選類型和隱式可選類型兩者有什麼不同,使用場景又是怎樣? 當時問題就這麼蹦出來…

  1. 首先必須明確可選類型定義:兩種情況:值存在且等於x(程序中的賦值);值不存在=nil。那麼也就是說 explicit Optionalimplicit Optional 都存在值不存在情況嘍。

  2. 顯示可選類型總是要通過一些手段(比如if-let)來檢查值是否存在,然後再解包取值()。確實這麼做能夠提高安全性,但是有時候過於繁瑣。就比如有些情況是這樣的,可選類型一旦經過初始化後,一直都是有效的。既然我們已經明確知道可選類型變量初始化之後很長一段時間,或者說始終,都是有值的。那麼我們還要每次進行繁瑣的解包行爲呢?(ps:用if-let先可選綁定取值或者用!強制解包取值)。

  3. 因此我們使用隱式可選類型(implicity Optional),即類似(var para:Type!)來聲明。這樣做的好處用一個簡單實例來表示:

    var str:String! = "hello world"     //初始化賦值
    
    //注意沒有使用 ! 來解包了 而是偷偷幫我們解包取值了 這也就是爲啥叫做隱式解包
    //打印結果就是hello world 與Optional("hello world")不同
    println(str)                        
    
  4. 但是需要強調的是假如變量用來存儲的值是有可能沒有的,最好還是使用顯示可選類型,也就是帶有?的。那麼什麼時候用隱士可選類型呢?

  5. 你會注意一些IBOutlet都是帶有!的隱式可選類型。那是因爲一旦Storyboard初始化完成,那麼這些接口都是賦值完畢不再改動,以後用起來就不需要再去顯示解包了,這裏注意(不是沒有了解包,而是偷偷地 自動地幫你解包),不再需要每個都判斷值是否存在,也不必用!來解包取值,直接使用即可。

  6. 再舉個例子加深下自身理解。就好比平常用的,控制器中總會有那麼些聲明:

    class ViewController:UIViewController{

    //請看這裏 變量聲明
    var searchResult :Result!       //這裏是用 ! 還是 ?
    
    override viewDidLoad(){
    ...
    }
    ...
    

    }

    我現在這麼理解,假設當然處於一個其他ControllerA中,有一個button跳轉到這個ViewController,並且傳遞給searchResult值,你必然肯定值是存在的(ps:當然在SB中跳轉 我們會在prepareForSegue中來設置)。一旦賦值好就不改變了,那麼自然就是用隱式可選類型恰當。假如這個searchResult是在當前ViewController下通過http Get請求獲取,自然存在沒有值的情況,那麼用?合適吧。

    不過希望自己能理解的是,假如隱式可選類型等於nil了,那麼你在使用時不做判斷處理直接拿來使用必定要拋出一個錯誤。 所以你在使用隱式可選類型之前一定要考慮,是否一旦賦值必定不會再存在值爲空的情況。假如還是有可能,建議用?


目前就理解到這個程度。若以後還有新的理解 或者上述表達哪裏不準確,我將進一步修改。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章