0000_0000_0000_0100.Optional<T> 可选类型闲谈

前端之家收集整理的这篇文章主要介绍了0000_0000_0000_0100.Optional<T> 可选类型闲谈前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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了,那么你在使用时不做判断处理直接拿来使用必定要抛出一个错误。 所以你在使用隐式可选类型之前一定要考虑,是否一旦赋值必定不会再存在值为空的情况。假如还是有可能,建议用?

目前就理解到这个程度。若以后还有新的理解 或者上述表达哪里不准确,我将进一步修改

猜你在找的Swift相关文章