swift optionals

JerryXia 发表于 , 阅读 (18)

swift中一个objective-c没有的概念就是optionals. optionals在作用上类似于objc中的nil pointer, 但更加安全。

Optional的基础用法

class Animal {    func name() -> String { return "animal" }}var a1: Animal?a1 = Animal()a1!.name()   // animalvar a2: Animal?a2?.name()   // nila2!.name()   // runtime errorvar a3: Animal = nil // compiler errorvar a3: Animal = a2  // compiler error

optional有两种状态,一种是nil, 一种是某个对象的值.

使用在类型名后加?的方式来创建一个optional.

optional可以像赋予对象,也可以赋予nil。

普通变量不可以赋nil, 也不可以赋optional。(均为 compiler error)

当需要取optional里面对象的值时,使用?或者!,该过程称为unwrap,会把optional变为普通变量. ?类似于objc中的nil pointer,当optional变量为nil时进行no-op, 不会报错; 而!当变量为nil时会crash,类似于其他语言中的NPE.

有了optional后,我们就可以方便的使用类似objc中nil pointer的特性,但是同时又可以用crash来及时的找出程序中的bug,可以说是兼具两者的优点。

implicit unwrap (隐式解包)

var a2: Animal?a2?.name()   // nilvar a3: Animal! = a2 // a3 = nila3.name()  // crashvar a4: Animal = a2! // crash

当我们希望把一个optional解开时, 可以用在类名后加!的方式。这样得到的变量a3类型仍为optional,只是在调用其方法时会自动用!来解开,不需要再显式解包。注意a3和a4的不同:a3是一个optional,而a4是一个普通变量,所以在调用a2!的时候会直接crash。

隐式解包在和objc代码接口时常常会用到,因为objc里的类变量对于swift看来都是optional。

optional binding

使用if let可以把check optional和unwrap一起进行,如果不为nil则调用if内部,同时将optional转化为实际类型:

if let x = someOptional {	// someOptional is not nil, x gets the value}

optional chaining

可以使用?将多个optional调用连接,任何一步optional为nil都为noop。例如:

x.prop1?.prop2?.method()

方法+?

objc中使用respondsToSelector:来判断一个对象是否能调用某个方法。在swift中,可以直接用someObj.method?()来完成同样的功能,如果method不存在就是no-op.

构造函数+?

init?() 可以用来定义一个可失败的构造函数。当构造失败时返回nil。

类型转换

swift在进行类型转换时,使用as关键字。向上转换(转换为父类)使用as,编译器可以自动判断其安全性;向下转换时使用as?会生成optional, 转换不成功为nil;使用as!会自动unwrap optional,如果转换失败会crash。

Optional的定义

swift 中的Optional 定义如下(简化了很多细节):

public enum Optional<Wrapped> {    case None    case Some(Wrapped)}

可以看到,Optional其实是个enum, 所以以下代码是等效的:

var a1: Animal?a1 = Animal()if let a = a1 {    print(a.name())}// pattern matchingif case .Some(let a) = a1 {    print(a.name())}// pattern matching using switchswitch(a1) {case .None:    print("nil")case .Some(let a):    print("animal \(a.name())")}

所以,?, !等,都是一些语法糖,都可以转换为普通的pattern matching代码。