【转】Swift之 ? 和 !

原文地址:http://joeyio.com/ios/2014/06/04/swift---/ios

 Swift语言使用var定义变量,但和别的语言不一样,Swift里不会自动给变量赋初始值,也就是说变量不会有默认值,因此要求使用变量以前必需要对其初始化。若是在使用变量以前不进行初始化就会报错:swift

var stringValue : String //error: variable 'stringValue' used before being initialized //let hashValue = stringValue.hashValue // ^ let hashValue = stringValue.hashValue

上面了解到的是普通值,接下来Optional值要上场了。经喵神提醒,Optional实际上是个enum,里面有NoneSome两种类型。其实所谓的nil就是Optional.None, 非nil就是Optional.Some, 而后会经过Some(T)包装(wrap)原始值,这也是为何在使用Optional的时候要拆包(从enum里取出来原始值)的缘由, 也是PlayGround会把Optional值显示为相似{Some "hello world"}的缘由,这里是enum Optional的定义:安全

enum Optional<T> : LogicValue, Reflectable { case None case Some(T) init() init(_ some: T) /// Allow use in a Boolean context. func getLogicValue() -> Bool /// Haskell's fmap, which was mis-named func map<U>(f: (T) -> U) -> U? func getMirror() -> Mirror }

声明为Optional只须要在类型后面紧跟一个?便可。如:app

var strValue: String? //?至关于下面这种写法的语法糖 var strValue: Optional<String>

上面这个Optional的声明,意思不是”我声明了一个Optional的String值”, 而是”我声明了一个Optional类型值,它可能包含一个String值,也可能什么都不包含”,也就是说实际上咱们声明的是Optional类型,而不是声明了一个String类型,这一点须要铭记在心。ide

建议再读一遍上段文字。ui

一旦声明为Optional的,若是不显式的赋值就会有个默认值nil。判断一个Optional的值是否有值,能够用if来判断:spa

if strValue { //do sth with strValue }

而后怎么使用Optional值呢?文档中也有提到说,在使用Optional值的时候须要在具体的操做,好比调用方法、属性、下标索引等前面须要加上一个?,若是是nil值,也就是Optional.None,会跳事后面的操做不执行,若是有值,就是Optional.Some,可能就会拆包(unwrap),而后对拆包后的值执行后面的操做,来保证执行这个操做的安全性,好比:设计

let hashValue = strValue?.hashValue

strValue是Optional的字符串,若是strValue是nil,则hashValue也为nil,若是strValue不为nil,hashValue就是strValue字符串的哈希值(其实也是用Optional wrap后的值)code

另外,?还能够用在安全地调用protocol类型方法上,好比:索引

@objc protocol Downloadable { @optional func download(toPath: String) -> Bool; } @objc class Content: Downloadable { //download method not be implemented } var delegate: Downloadable = Downloadable() delegate.download?("some path")

由于上面的delegate是Downloadable类型的,它的download方法是optional,因此它的具体实现有没有download方法是不肯定的。Swift提供了一种在参数括号前加上一个?的方式来安全地调用protocol的optional方法。

另外若是你须要像下面这样向下转型(Downcast),可能会用到 as?

if let dataSource = object as? UITableViewDataSource { let rowsInFirstSection = dataSource.tableView(tableView, numberOfRowsInSection: 0) }

到这里咱们看到了?的几种使用场景: 1.声明Optional值变量 2.用在对Optional值操做中,用来判断是否能响应后面的操做 3.用于安全调用protocol的optional方法 4.使用 as? 向下转型(Downcast)  

另外,对于Optional值,不能直接进行操做,不然会报错:

//error: 'String?' does not have a member named 'hashValue' //let hashValue = strValue.hashValue // ^ ~~~~~~~~~ let hashValue = strValue.hashValue

上面提到Optional值须要拆包(unwrap)后才能获得原来值,而后才能对其操做,那怎么来拆包呢?拆包提到了几种方法,一种是Optional Binding, 好比:

if let str = strValue { let hashValue = str.hashValue }

还有一种是在具体的操做前添加!符号,好吧,这又是什么诡异的语法?!

直接上例子,strValue是Optional的String:

let hashValue = strValue!.hashValue

这里的!表示“我肯定这里的的strValue必定是非nil的,尽情调用吧” ,好比这种状况:

if strValue { let hashValue = strValue!.hashValue }

{}里的strValue必定是非nil的,因此就能直接加上!,强制拆包(unwrap)并执行后面的操做。 固然若是不加判断,strValue不当心为nil的话,就会出错,crash掉。

考虑下这一种状况,咱们有一个自定义的MyViewController类,类中有一个属性是myLabel,myLabel是在viewDidLoad中进行初始化。由于是在viewDidLoad中初始化,因此不能直接声明为普通值:var myLabel : UILabel,由于非Optional的变量必须在声明时或者构造器中进行初始化,但咱们是想在viewDidLoad中初始化,因此就只能声明为Optional:var myLabel: UILabel?, 虽然咱们肯定在viewDidLoad中会初始化,而且在ViewController的生命周期内不会置为nil,可是在对myLabel操做时,每次依然要加上!来强制拆包(在读取值的时候,也能够用?,谢谢iPresent在回复中提醒),好比:

myLabel!.text = "text" myLabel!.frame = CGRectMake(0, 0, 10, 10) ...

对于这种类型的值,咱们能够直接这么声明:var myLabel: UILabel!, 果真是高(hao)大(gui)上(yi)的语法!, 这种是特殊的Optional,称为Implicitly Unwrapped Optionals, 直译就是隐式拆包的Optional,就等于说你每次对这种类型的值操做时,都会自动在操做前补上一个!进行拆包,而后在执行后面的操做,固然若是该值是nil,也同样会报错crash掉。

var myLabel: UILabel! //!至关于下面这种写法的语法糖 var myLabel: ImplicitlyUnwrappedOptional<UILabel>

那么!大概也有两种使用场景 1.强制对Optional值进行拆包(unwrap) 2.声明Implicitly Unwrapped Optionals值,通常用于类中的属性 

Swift是门新生的语言,咱们有幸见证了它的诞生,激动之余也在佩服苹果大刀阔斧的推出一个新的语言替代一个已经比较成熟语言的魄力,今天在知乎日报上看到一个回答是说Swift是一门玩具语言,正当想去吐槽,发现回答已经被删除了。我的认为苹果是很认真的推出Swift的,从Swift的各类细微的设计也能看的出来。

另外这两个小符号就花费了我很多的时间来理解,可能依然会有错误和不妥之处,欢迎你们指正,本文旨在抛砖引玉。除此以外,Swift还有不少很棒的特性,WWDC 2014 会有四五个和Swift语言相关的Video,你们也能够去关注一下。

最后要感谢喵神的纠正了多处有问题的地方,thx, have fun!

相关文章
相关标签/搜索