swift中的optional

作者:周星 发布:2014-11-06

       本次分享的内容为 swift 中的 optional 数据结构,本文会先简单讲述 optional 的一般用法,然后结合IOS 开发,最后从源码的角度来分析optional。

       swift 语言里有一种比较“特殊”的数据类型 —— optional,当值可能不存在的时候,我们使用 optional,对比一下 ruby 语言,ruby 中可以直接给变量赋值为 nil:

a = nil

       在 swift 语言中,optional 可以是任意类型,swift 不会给自动给变量赋初始值,所以定义变量时必须给初始值,否则就会报错,这个时候 optional 就派上了用场:

var str: String?                           // nil

       通过这样的定义,即在声明的类型后面加一个问号(?),变量 str 即指定为了 nil,未来在程序中我们就可以根据需求对其赋值等,下面我们来看一下如何使用我们定义的 optional 类型:

str = "hello world"                        // {Some "hello world"}

       上面的代码是为我们的 optional 类型的变量 str 赋值为 hello world,在使用 optional 的时候要具体情况具体分析,比如调用方法、属性、下标索引时要在变量后加一个问号,否则会报错,根据 optional chaining ,带上问号询问是否响应这个方法,类似于 ruby 中的 respond_to? ,如果值为 nil,则当然不能响应后面的方法,问号后面的代码全部跳过。

str.isEmpty                                // "str?" does not have a member named isEmpty
str?.isEmpty                               // nil

       下面再介绍一下解包(unwrap)的概念,如上所述,直接使用 optional 变量会报错,必须要取出这个变量的值才能操作,这个过程就是解包(unwrap),解包有几种方法,其中最常见的就是在变量后面加感叹号(!)

str!                                       // 直接报错,因为 str 为 nil
str = "xxx"                                //  {Some "xx"}
str!                                       // "xx"

还有一种方法是optional binding:

var optionalString: String? = "Hello"           
optionalString == nil

var optionalName: String? = "world"
var greeting = "Hello!"                  
if let name = optionalName {
    greeting = "Hello, \(name)"             // "hello,world"
}

       现在我们结合一下 IOS 开发中实际的例子,我们在建项目后有一个给定的类 ViewController,我们拖拽一个控件 UILabel 并画线,假设我们生成的这个变量为 titleLabel,我们要把 titleLabel 在 viewDidLoad 方法中初始化,因为这个变量在 viewDidLoad 中初始化,所以就不能声明为普通变量并给其一个初始值,在 viewController 整个生命周期内这个变量都不会为 nil,我们看到 XCODE 怎么生成的声明代码?

@IBOutlet weak var titleLabel: UILabel!               // XCODE 6.1  SDK8.1

       在声明类型后面加一个感叹号,我们把它称为隐性解包(Implicitly Unwrapped Optionals),官方的文档上有非常详细的介绍(上面的代码正是隐性解包的适用场景),调用的时候直接使用变量即可(网上某转载量较高的博文在处有较大错误,大家可以亲自试验),就不需要加感叹号解包了,如果 titleLabel 没有赋值,变量直接为 nil。

下面我们看一下 swift 源码是怎么定义 optional 的:

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

    /// Construct a `nil` instance.
    init()

    /// Construct 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: ())
}

       optional 实际是个枚举,里面有 None 和 Some(T) 两种类型,Optional.None 就是 nil,而非 nil 就是 Optional.Some,然后some(T) 再将其包装一下,这就是我们取值时需要拆包(unwrap)的原因。也是 playground 中出现 {some: "xx"}的原因。


       博主也是 swift 新手,刚刚对 optional 有一些自己的理解,如果您有些迷茫,那没有关系,因为博主回头读一遍发现也有些拗口,欢迎一起讨论,如果您对本文有什么意见或建议,请联系博主

支付宝扫码赞助博主


评论(0)