Swift - ?和!的学习

  最近在优化一个项目的过程,过程中发现之前开发时由于刚接触 Swift 的原因,在 Swift 中的类里使用了很多 OC 的写法,比如字典数组对象会习惯性用 NSDictionaryNSArray来初始化,而不是用 [KeyType: ValueType]() 或是 [SomeType]() 这种类型来实例化变量。虽然在使用上没有什么问题,但看起来多少有点。。。不优雅。
  当我把大部分类型都修改成 Swift 中的写法后(部分未修改是因为使用 String 类型来给文本做截取和富文本定义,实在不如 NSString 顺手,这种不顺手让我不由想起 Stack Overflow 上看到的一个评论:I thougt i already getting along well with Swift.)发现,原来一些变量是否为空的判断中,使用 Swift 里的 optional 类型会方便很多。
  比如解析一个 json 数据,如果层级多而且里面每个元素都是不确定的,那么可能就需要每个层级都判一次空。而如果使用 ? 来设置当前对象为可选值,只需要在最后一层实际使用到对象值时,判一次空就 OK 了。
  对于 ? 和 ! 的区别和总结,网上有很多文章,在这里就不重复造轮子了。下面就对这个 optional 的自己两个疑问做个记录。   

? 和 ! 是表示两种不同的类型吗,一种是可以为空,一种不可以为空?

  刚开始使用的时候没做深入了解,以为 optional 中的 ? 和 ! 和 let 声明不可变变量,var 声明可变变量。? 和 ! 是一组彼此相对只是含义不同的两个符号。但深入了解了一下,发现并不是这样,引用两段官方的文档:

You use the Optional type whenever you use optional values, even if you never type the word Optional. Swift’s type system usually shows the wrapped type’s name with a trailing question mark (?) instead of showing the full type name. For example, if a variable has the type Int?, that’s just another way of writing Optional. The shortened form is preferred for ease of reading and writing code.

The types of shortForm and longForm in the following code sample are the same:

1
2
let shortForm: Int? = Int("42")
let longForm: Optional<Int> = Int("42")

  这里的意思是说当你使用 Optional 类型时的值,即使在初始化时没有用“Optional”这个单词指定类型,在 Swift 中也可用 ? 代替。即 Int? 等于 Optional<Int>。那按照之前我的理解,是否 ! 也是某个 Not Optional 单词的代替?后面官方文档就有提到了:

When you’re certain that an instance of Optional contains a value, you can unconditionally unwrap the value by using the forced unwrap operator (postfix !). For example, the result of the failable Int initializer is unconditionally unwrapped in the example below.

  意思是说 ! 是代表一种 Unconditional Unwrapping 的运算符,而并不是作为一种类型的表达。   

关于 Unconditional Unwrapping

  Unconditional Unwrapping 怎么理解,直译的话叫无条件展开,专业术语叫强制拆包。为什么使用 Optional 类型会需要强制拆包,如果使用 ! 运算符意味着强制拆包,那不使用 ! 时,Optional 是否还会做拆包的处理呢?
  仍然回到官方文档,有这句:

The Optional type is an enumeration with two cases. Optional.none is equivalent to the nil literal.

  也就是说 Optional 是一个默认带有 Optional.none 枚举类型的包装。所以使用时我们必须按官方说的:

You must unwrap the value of an Optional instance before you can use it in many contexts.

其他

  基于以上的学习和理解,我们可以来解读以下一些写法:

初始化
1
2
3
4
let value:NSString = nil //错误写法,未指定 Optional,所以不可以被赋值为空
let value:NSString! //如果后续未赋值而直接使用则会崩溃
let value:NSString? = nil //同下,如果后续 value 未被赋值,他会默认等于 nil
let value:NSString?
转换类型
1
2
3
4
5
6
7
8
9
10
let array:NSArray = NSMutableArray.init(object: "111")
/*
(111)
*/
print(array as! NSMutableArray)

/*
Optional(<__NSArrayM 0x7b790430>(111))
*/
print(array as? NSMutableArray)
方法定义
1
2
3
4
5
6
7
8
//可传空值
func buttonClick(sender: UIButton?){
//....
}
//不可传空值
func buttonClick(sender: UIButton){
//....
}
1
2
3
4
5
let fruitDic: [String: String] = ["apple":"red","banana":"yellow"]
let apple: String! = fruitDic["apple"]! // String! 可以直接写成 String,这里只是为了直观阅读
let banana: String? = fruitDic["apple"]
let blueberry: String! = fruitDic["blueberry"] ?? ""
let orange: String? = fruitDic["orange"]