Swift可选类型知识梳理

2019-11-09  本文已影响0人  _小沫

Swift中加入了可选类型Optional,用来处理值可能缺失的情况。可选类型表示两种可能: 或者有值, 你可以解析并访问这个值, 或者根本没有值;

可选类型的作用

static const NSInteger NSNotFound = NSIntegerMax;
#define NSIntegerMax    LONG_MAX

不过这种策略是有问题的,因为这个哨岗值不管从哪个角度看都是一个真实值;你也可能会忘记检查这个值而不小心使用了它;而可选类型很好的处理了这种情况;

可选类型的本质

Optional结构如下:

public enum Optional<Wrapped> : ExpressibleByNilLiteral {

    /// The absence of a value.
    ///
    /// In code, the absence of a value is typically written using the `nil`
    /// literal rather than the explicit `.none` enumeration case.
    case none

    /// The presence of a value, stored as `Wrapped`.
    case some(Wrapped)

    ....
}

我们可以这样声明一个可选整型:

var opValue: Optional<Int> = Optional.init(1)
// or
// var opValue: Optional<Int> = 1

这个声明可以用?语法糖简化表示:

var opValue: Int? = 1

使用switch解包得到关联值:

switch opValue {
case .none:
    print("nil")
case .some(let value):
    print(value)
}

或使用if case语句:

if case Optional.some(let value) = opValue {
    print(value)
}else {
    print("nil")
}

因为遵循了字面量协议上面的解包可以替换为:

switch opValue {
case nil:
    print("nil")
case .some(let value):
    print(value)
}

Swift 的 nil 和 Objective-C 中的 nil 并不一样。在 Objective-C 中,nil 是一个指向不存在对象的指针。在 Swift 中,nil 不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选状态都可以被设置为 nil,不只是对象类型。

强制解析

可以使用 if 语句和 nil 比较来判断一个可选值是否包含值;
当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号!来获取值。这个惊叹号表示“我知道这个可选有值,请使用它”,这就是可选值的强制解析;

if opValue != nil {
    print(opValue!)
}else {
    print("nil")
}

使用 ! 来获取一个不存在的可选值会导致运行时错误。使用 ! 来强制解析值之前,一定要确定可选包含一个非 nil 的值。

可选绑定

if let value = opValue {
    print(value)
}

也可以在同一个if语句中绑定多个值,当多个可选值都有解析值时条件成立:
只有opValue1,opValue2都有值时才会调用输出结果:

let opValue1: Int? = 1
let opValue2: Int? = nil
if let v1 = opValue1, let v2 = opValue2 {
    print(v1,v2)
}
    guard let v = opValue else { return }
    print(v)

一个比较明显的例子:

if let v1 = opValue1 {
    if let v2 = opValue2 {
        if let v3 = opValue3 {
            print(v1,v2,v3)
        }
    }
}

guard let v1 = opValue1 else { return }
guard let v2 = opValue2 else { return }
guard let v3 = opValue3 else { return }
print(v1,v2,v3)

guard let同样可以绑定多个值:

guard let v1 = opValue1,let v2 = opValue2,let v3 = opValue3 else { return }
print(v1,v2,v3)

if 条件语句中使用常量和变量来创建一个可选绑定,仅在 if 语句的句中(body)中才能获取到值。相反,在 guard 语句中使用常量和变量来创建一个可选绑定,仅在 guard 语句外且在语句后才能获取到值;

另外,guard并不局限于绑定上,它也能够接受任何在if语句中能接受的条件;附:使用 guard 的正确姿势

可选链

可选链Optional Chaining:多个连续的调用可以被链接在一起形成一个调用链,如果其中任何一个节点为空(nil)将导致整个链调用失败。也就是说可以将可选值的调用链接起来;

let str: String? = ""
str?.uppercased().lowercased()
delegate?.callback()

和OC不同的是,如果没有值,那么这里的问号对于代码的阅读者来说是一个清晰的信号,表示方法可能不会调用;

var str: String? = ""
if str != nil {
    str = str?.lowercased()
    if str != nil {
        str = str?.uppercased()
        print(str)
    }
}

if let result = str?.lowercased().uppercased() {
    print(result)
}

隐式解析

有时候在程序架构中,第一次被赋值之后,可以确定一个可选类型总会有值。在这种情况下,每次都要判断和解析可选值是非常低效的,因为可以确定它总会有值。这种情况我们就可以定义隐式解析可选类型(implicitly unwrapped optionals)。把想要用作可选的类型的后面的问号(String?)改成感叹号(String!)来声明一个隐式解析可选类型。

let opValue: Int! = 1
print(opValue + 1)

如果你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一个惊叹号一样。

上一篇 下一篇

猜你喜欢

热点阅读