前提:Swift中有规定:对象中的任何属性在创建时,都必须要有明确的初始化值

1.定义可选类型

方式一:常规方式(不常用)

var name : Optional<String> = nil

方式二:语法糖(常用)

var name:String? = nil

Optional理解:

  Optional也是Objective-C没有的数据类型,是苹果引入到Swift语言中的全新类型,它的特点就和它的名字一样:可以有值,也可以没有值,当它没有值时,就是nil。此外,Swift的nil也和Objective-C有些不一样,在Objective-C中,只有对象才能为nil,而在Swift里,当基础类型(整形、浮点、布尔等)没有值时,也是nil,而不是一个初始值,没有初始值的值,是不能使用的,这就产生了Optional类型。定义一个Optional的值很容易,只需要在类型后面加上问号(?)就行了:

let nameStr: String?

  Optional值和非Optional值的区别就在于:Optional值未经初始化时也为nil,非Optional未初始化时什么都没有,如果直接使用会报错:

//未被初始化,但是是一个Optional类型,为nil

var nameStr: String?

str //输出nil

//未被初始化,也不是Optional类型

var nameStr2: String

str2    //使用时出错

Optional拆包:

  Optional类型的值不能被直接使用,当需要用时要显式拆包,以表明我知道这个Optional是一定有值的:拆包的方式是直接在变量后加!

var nameStr: String? = "Hello World!"

nameStr     //{Some "Hello World!"}

nameStr!    //Hello World!

  拆包的原因是因为Optional类型其实是一个枚举:

enum Optional<T> : Reflectable, NilLiteralConvertible {

    case None

    case Some(T)

    init()

    init(_ some: T)

    /// Haskell's fmap, which was mis-named

    func map<U>(f: (T) -> U) -> U?

    func getMirror() -> MirrorType

    static func convertFromNilLiteral() -> T?

}

拆包的作用就是将值取出来。

隐式拆包:

  除了显式拆包,Optional还提供了隐式拆包,通过在声明时的数据类型后面加一个感叹号(!)来实现:

var nameStr: String! = "Hello World!"

nameStr //Hello World!

  可以看到没有使用(?)进行显式的折包也得到了Some中的值,这个语法相当于告诉编译器:在我们使用Optional值前,这个Optional值就会被初始化,并且总是会有值,所以当我们使用时,编译器就帮我做了一次拆包。如果你确信你的变量能保证被正确初始化,那就可以这么做,否则还是不要尝试为好。

Optional Binding

var count: Int?

count = 100

if count != nil {

    "count is " + String(count!)    //count is 100

} else {

    "nil"

}

上面代码,如果判断为真,下面将进行拆包,为了避免在条件判断语句后执行一次或更多次的拆包,Swift引进了Optional Binding,我们就可以这样做

var count: Int?

count = 100

if let validCount = count {

    "count is " + String(validCount)    //count is 100

} else {

    "nil"

}

通过在条件判断语句中(如if、while等)把Optional值直接给一个临时常量,Swift会自动检测Optional是否包含值,如果包含值,会隐式的拆包并给那个临时常量,在接下来的上下文中就能直接使用这个临时常量了

 

注意:强制解包是危险操作,容易导致程序崩溃

建议在强制解包前,先对可选类型进行判断,判断是否为nil

可选绑定

写法一:(不常用)因为每次解包要创建一个新的变量

if let tempName = name{
print(tempName)
}

解释:1.判断name是否有值,如果没有不执行{}内容,如果有值,系统会自动将name解包,并且直接复制给tempName

写法二:(常用),就近原则

if let name = name{
print(name)
}