Normal Type 和 Optional Type(可选类型)
Optional是swift不同于C以及Objective-c的一种新概念。引进了这个概念之后,我们可以把类型分为普通类型(例如, String, Array ...)和可选类型(Optional Type)。
swift中使用普通类型表示值一定存在,用可选类型(Optional Type)来表示其所对应的值可能存在可能为nil。
Optional Type 的本质是一个枚举类型,它枚举的是None(nil)和NormalType,如下所示:
enum Optional {
case None
case Normal(T)
}
复制代码
所以其实OptionalType和NormalType是一个包含关系。
我们在写代码的时候也会发现,对于一个要传入NormalType的函数,如果传入一个有枚举情况的Optional的值是会报错的:
open func appending(_aString:String) ->String
复制代码
var stringA : String = "a"
let stringB : String? = "b"
stringA.appending(stringB) // 编译错啦
复制代码
Optional Type的分类
Optional Type又分为Normal Optional(普通)和Implicitly Unwrapped Optional(隐式拆包)。
普通的可选类型用 '?' 来声明,表示该值可能存在可能为nil。相当于声明了一个包含 Optional.None和Optional.Some(T)的枚举类型。
隐式拆包用 '!' 来声明,表示确认该值不为nil,一定存在。相当于声明了Optional.Some(T)。
需要注意的是,声明为隐式拆包Optional的对象值可以为nil,也就是说 'let string : String! = nil' 编译器完全是可以通过的。但是在之后访问该对象值时,会抛出异常。这和Optional Type的拆包有关。
做了个实验:
var stringa : String! = nil
let stringb :Character? ="a"
stringa?.append(stringb!) // 结果为 nil
stringa.append(stringb!) // 崩溃啦
复制代码
我们发现尽管stringa是隐式拆包的Optional类型,但是通过 '?' 来访问stringa 也是可以成功操作的,不会引发崩溃。由此猜想,
stringa?.append(stringb!)
复制代码
其实干了这些事:
if stringa != nil {
stringa!.append(stringb!)
} else {
return
}
复制代码
由此可以得出结论,隐式拆包的Optional只是给了Optional自动拆包的权限,并不代表这个值不能够为nil。o((⊙﹏⊙))o.
Optional Type的拆包
拆包其实相当于switch & case,如下所示:
var y = x!
switch x {
case Some(value) : y = value
case None: // raise an exception
}
复制代码
所以要确保x确实有值的情况下再进行拆包。
拆包的几种比较安全的办法:1)if 语句 + 强制拆包(!);2)Optional Binding (if let);
结论
1. 无论声明的String?还是String!其实都是一个Optional,所以值都可能为nil;
2. 声明为隐式拆包的Optional(例如,String!),在取值时只是省略了判断其值是否为nil的过程。所以一定要在确认值不可能为nil的情况下再使用为隐式拆包;
3. 最安全的确保一个值不为nil的情况是声明为NormalType;