Swift-?和!的区别

Swift 是一种新的编程语言,用于编写iOS,OS X 和 watchOS应用程序。Swift 结合了 C 和 Objective-C 的优点并且不受 C 兼容性的限制。Swift 采用安全的编程模式并添加了很多新特性,这将使编程更简单,更灵活,也更有趣。Swift 是基于成熟而且倍受喜爱的 Cocoa 和 Cocoa Touch 框架,它的降临将重新定义软件开发。

今天我们的主角是可选类型?和!

Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值,也就是说变量不会有默认值,所以要求使用变量之前必须要对其初始化。如果在使用变量之前不进行初始化就会报错:

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

Optional简介

讲到这里,我们的主角就要正式登场了——OptionalOptional其实是一个enum枚举值,它有两个值:NoneSomeOptional.None其实就是nil,Optional.Some就是非nil,它会通过Some(T)来进行Wrap包装原始值,这也是为啥使用Optional类型的时候要进行拆包unWrap(从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只需要在类型后面紧跟一个?或者!即可,如:

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

上面的?这个Optional可选项类型声明,意思是我声明了一个Optional类型,而不是声明了一个String类型,它可能包含一个String值,也可能不包含,不包含默认值就为nil。我们可以通过if判断来区分是否为nil:

if strValue {
    //do something with strValue
}

那么我们怎么使用Optional可选类型的值呢?直接在后面加上一个?号即可。如果是nil值,也就是Optional.None,会跳过后面的操作不执行,如果有值,也就是Optional.Some,就会进行unWrap拆包操作,比如:

//正确
let hashValue = strValue?.hashValue
//错误
let hashValue = strValue.hashValue

有一种特殊情况,假如我们非常肯定strValue一定是非nil的,我们也可以采用强制拆包处理:使用!

let hashValue = strValue!.hashValue

!就代表强制拆包,假如strValue是nil,你强制拆包也会报错

Optional可选类型?的使用场景

  1. 声明Optional变量

    var strValue : String?
    
  2. 用在对Optional值操作中,用来判断是否能响应后面的操作

    let hashValue = strValue?.hashValue
    
  3. 用于安全调用protocol的optional方法

    @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")
    
  4. 使用 as? 向下转型

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

Optional可选类型!的使用场景

  1. 强制对可选类型Optional进行拆包

    let hashValue = strValue!.hashValue
    
  2. 声明隐式拆包,一般用于类中的属性

    var strValue : String!