(对于可选类型的理解能够参见猫神的这篇行走于 Swift 的世界中,在此整理一些关键的部分。)git
Swift 中的 Optinal Value 就像是一个盒子,可能装着值,也可能什么都没装。github
咱们能够用 ?
定义一个可选类型的整数 :swift
var num: Int? num = nil //nil num = 3 //{Some 3}
可选类型的真实身份实际上是 Optional
类型,经常使用的 ?
是 Apple 提供的语法糖。使用 Optional
的写法是这样的:app
var num: Optional<Int> num = Optional<Int>() // nil num = Optional<Int>(3) // {Some 3}
点进去看下 Optional
的定义:ide
enum Optional<T> : Reflectable, NilLiteralConvertible { case None case Some(T) /// Construct a `nil` instance. init() /// Construct a non-\ `nil` instance that stores `some`. init(_ some: T) /// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`. func map<U>(f: (T) -> U) -> U? /// Returns a mirror that reflects `self`. func getMirror() -> MirrorType /// Create an instance initialized with `nil`. init(nilLiteral: ()) }
这样一来,var num: Int? = 3
其实就是 Optional.Some(3)
。post
在这里,?
声明了一个 Optional<T>
类型的变量,而后作了判断:.net
Optional.None
init(_ some: T)
初始化并返回 Optional.Some(T)
。在遭遇可选类型的时候,咱们能够在 Optional 变量后面加上 !
进行强制解包。这样虽然减小了代码量,可是容易带来隐患,使用的时候务必要慎重。就像是过马路同样,必定要仔细看好两边车辆,不然悲剧随时可能发生。code
而实际上,不少时候能够避免使用 !
,用其余方法取而代之。排序
来看这样一个例子:ci
let ages = [ "Tim": 53, "Angela": 54, "Craig": 44, "Jony": 47, "Chris": 37, "Michael": 34, ] let people = sorted(ages.keys, <).filter { ages[$0]! < 50 } println(people) // "[Chris, Craig, Jony, Michael]"
在这里先对 ages
进行了排序,而后筛选出年纪小于 50 的人。由于是对字典取值,会出现 nil
,因此 ages[$0]
是 optional 的,须要进行解包。
固然也能够用 if let
:
let people = sorted(ages.keys, <).filter { if let age = ages[$0] { return age < 50 } return false; }
可是原本一行就能搞定的问题却拖沓到了五行才解决。实际上,换个思路,咱们彻底不须要遭遇可选类型:
let people = filter(ages) { $0.1 < 50 }.map { $0.0 }.sorted(<)
filter
中 $0 表示传入的 key-value ,$0.1 表示 value,map
中 $0 表示传入的 key-value ,$0.0 表示 key 。或许这样可读性比较差,能够经过 tuple 包装一下入参:
let people = filter(ages) { (k,v) in v < 50 }.map { (k,v) in k }.sorted(<)
在平时的开发中,咱们能够用 if let
或者 ??
替换掉 !
。若是确实确实确定不会出问题再去用 !
。
一样是 !
符号,若是放在类型后面,则表示隐式解析可选类型 (Implicitly Unwrapped Optionals):
var num: Int! num = 1 // 1 num = nil // nil
经过 !
定义的变量,实质上只是对 Optional 的变量多了一层封装,帮咱们完成了本来须要手动解包的过程。
在什么场合下可使用隐式解析可选类型呢?
有些尴尬的状况,咱们想定义常量属性,无奈它的初始化依赖于其余属性值。若是你用可选类型,实在是麻烦,由于你确信无疑它确定会在调用以前就完成初始化,不多是 nil
,这个时候你能够用 !
进行定义。
举个例子:
class MyView : UIView { @IBOutlet var button : UIButton var buttonOriginalWidth : CGFloat! override func viewDidLoad() { self.buttonOriginalWidth = self.button.frame.size.width } }
这部份内容在 Day11 中有涉及,其实更好的方法是用 lazy 延时加载,再也不赘述。
隐式解析可选类型彷佛是为了照顾 objc 这个历史包袱而存在。好比 UITableView
中:
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell? { return nil }
咱们很清楚的知道,在调用的时候 tableView
和 indexPath
不可能为 nil
,若是还要 if let
这样解包实在是浪费时间。若是是纯粹的 Swift 语言写的,绝对不会定义成 optional 类型。
除了上述的状况2 ,其余状况都不应用 (包括状况1)。