摘要: 针对swift新增的安全类型optional类型的概念理解,以及在开发过程中的一些使用和注意事项。新手开发,仅已此文备忘,如有错误,还请斧正。
tips:本人开发经验不多,如文章有概念错误,还请各位指正,原创文章,转载请注明出处。
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)
}
optional类型是一个枚举类型,有两个枚举值:
None类型
Some(Wrapped)
这两个类型决定了optional类型的概念和含义,有值或者没有值:
1 optional.None表示该类型没有值,也就是nil。(特别声明,swift中的nil不在有指针含义,而是表示且仅表示optional的.None)。
2 optional.Some(Wrapped)这是表示有值的情况,Some类似于java或者c++的泛类型的含义,Wrapped 类似是封装的值。
optional的wrap和unwrap
使用optional类型,该类型会对赋值过程和取值进行一些处理。
1 赋值也被称为装包的过程(wrap),optional类型会获取当前值的类型和具体值,如int类型的数字100.当一个optional类型被赋值为这个值时,其实optional记录了对应的类型(some)int,和值部分(wrapped)100.
2 取值也被称为解包的过程(unwrap),optional根据记录的类型(some)如上面说的int,和值部分(wrapped)100,新建一个some(wrapped)同int(100)返回给程序
如何声明一个optional类型
声明optional类型十分简单,我们平常声明一个字符类型是这样的
let str : string = "hello world"
如果想声明一个optional类型,只需要
let str : string?
或者
let str : string! = @"hello world"
在类型后面加一个?或者!,那么你现在持有的这个变量就是optional类型变量了。十分简单。
?和!声明的optional类型的区别
上面我们提到了optional的使用过程有装包和解包的过程,装包过程是不需要我们自己处理,但是解包的过程是需要开发者简单处理的。而声明时使用?和!的不同就表现在解包的过程。
optional类型的解包方法有下面这些
直接在变量后面使用!进行解包
使用if或者guard语句进行解包
使用!声明的optional变量,使用时自动调用解包
第三点已经说出了使用!和?声明变量时的不同了,就是使用!声明的optional变量在后续的使用中,不需要再进行解包操作,当需要解包时,系统会对该变量自动解包处理。而使用?声明的optional变量则需要使用上面说明的1)或者2)其中一种方法解包,才能继续使用。
那么问题来了,既然能自动解包,那么都声明成!不就好了,还省事。optional是swift特别提出的安全类型,它的安全精髓就体现在解包这个步骤上。optional类型的解包是有崩溃的风险的。一个没有值也就是nil(optional.None)的optional变量,强行解包的话,程序是会直接crash。
var str : string!
print(str) //cash str is optional.none
输出时,你会得到一个error,要是在项目中,不进行判断直接对没有值的optional变量强行解包的话,程序会crash。
所以总结来说,会crash或者得到一个error的原因就是optional类型变量在解包那一刻没有值。所以在开发过程中,如果你的optional是用!声明的,你就得确保在它的生命周期内,它不可能是nil,这是使用!声明的前提。而使用?声明虽然要在每次使用之前解包,但是我们可以在解包的过程进行一些判断操作,当变量是nil时做一些合适的处理。
如何才是安全正确的解包姿势呢
1 使用!直接解包是粗暴的,是不温柔的
2 swift针对optional安全类型,特别对if和guard语句做了处理,使用if和guard语句解包是安全的,温柔的
var firstName :String?
if let tempName = firstName{
print(tempName)
}else{
print("firstName is nil")
}
if后面的的let语句就实现了安全解包的过程。如果firstName有值的话,tempName能获取到firstName的值。在if语句内,可以放心使用。
guard语句也有同样的效果
guard let tempName = firstName else{
print("firstName is nil")//nil时做一些特殊处理
return
}
print(tempName)
guard语句更加突出错误时的处理,还有一个优点就是,你let声明的tempName在guard语句外可以正常使用。
总结:optional是swift特别声明的安全类型,在使用过程中如果处理得当的话可以防止以前oc上很多因为数据没值导致的crash。个人还是比较推荐使用的,虽然有时候有些解包的过程感觉特别麻烦,但这都是一道道安全门,阻断了很多crash的诞生。