Swift可空类型和隐式展开可空类型

可空类型

可空类型指某个实例可能没有值,任何类型都可以用可空类型来说明一个实例可能是nil。可空类型让Swift这门语言更加安全。

一个可能为nil的实例应该被声明为可空类型。没有被声明为可空类型的实例不可能为nil。

  1. 声明时在类型后加?

    1
    2
    3
    4
    var errorCodeString: String?
    errorCodeString = "404"
    print(errorCodeString)
    //打印结果是Optional("404")
  2. 访问时需要强制展开,实例后加!

    1
    2
    3
    4
    if errorCodeString != nil{
    let theError = errorCodeString!
    print(theError)
    }
  3. 使用可空实例绑定展开

    强制展开时,如果可空实例没有值,程序会在运行时触发陷阱。所以对于可空类型实例的使用通常使用可空实例绑定。可空实例如果有值,就将其赋值给一个临时常量或变量,并且使这个常量或变量在条件语句的第一个分支中可以使用:

    1
    2
    3
    4
    5
    if let temporaryConstant = anOptional {
    //用temporaryConstant做一些事情
    } else {
    //anOptional没有值,也就是anOptional为nil
    }
  4. 展开多个可空实例

    赋值给临时常量或变量的条件之间用逗号分开:

    1
    2
    3
    4
    5
    var errorCodeString: String?
    errorCodeString = "404"
    if let theError = errorCodeString, let errorCodeInteger = Int(theError), errorCodeInteger == 404 {
    print("something has changed")
    }

隐式展开可空类型

  1. 使用的时候必须显式声明,访问时不需要展开;
  2. 没有显式声明的情况下,Swift只会使用普通可空类型进行类型推断;
  3. 安全性较差。
1
2
3
var errorCodeString: String!//声明为隐式展开可空类型
errorCodeString = "404"
print(errorCodeString)

如果隐式展开可空实例没有值时,访问其值会导致运行时错误。所以,只要某个实例有可能是nil,不要声明为隐式展开可空类型

1
2
3
var errorCodeString: String! = nil
let string1: String = errorCodeString//会触发陷阱,导致运行时错误
let string2 = errorCodeString //Swift会推断string2为可空实例,String?类型,值为nil

Swift会尽可能推断最安全的类型。所以对string2会推断为普通可空实例。要访问其值,必须展开可空实例,有助于代码的安全性。这个特性让类型推断在默认情况下是安全的,从而阻止不安全代码的扩散。

总结与思考

1
2
3
var aString : String
var bString : String?
var cString : String!

在访问以上三种方法声明的字符串的值的时候,有什么区别?

aString在初始化后只要被赋值过就会一直有值,不会为nil,也不能被赋值为nil

bString可能有值,可能为nil,访问时需要判空强制展开或可空实例绑定

cString可以赋值为nil,不需要强制展开,访问其值时,一旦为nil,将触发运行时错误