Swift中对optional value的安全处理——慎用问号叹号\”?!\”(消除swift项目里的\”?!\”)

我的博客原文:http://zyden.vicp.cc/swift-optional-value/
欢迎转载,请注明出处,谢谢

刚从oc转过来swift的朋友应该会感觉到swift中optional类型的粘人。是的,使用swift后就跟optional value撇不清关系了,刚上来的代码可能会是?!满天飞,这些?!肯定是要花功夫心思解决的。
swift要求编码者时时刻刻都对optional变量保持安全性思考,考虑该optional值会否为空(nil),若为空会不会带来影响,当然,不注意optional变量的安全使用,会很大概率为程序带来许多意料之外的问题,甚至crash。

容忍optional value不必要的" ?!"带来的害处:

容忍"?":在optional变量在传递过程中,不对其进行解包而保留"?",当真正使用该optional变量时,若其值为nil,则业务信息得不到传递,失去了业务的实现,也得不到对这种情况的处理。
容忍"!":而使用"!"对optional值进行强制解包的前提是编码者非常确定该optional值在该情况下不会为空(nil),对其强制解包成为非optional值使用,而过多不必要的"!"存在,相当于养着许多crash隐患,万一强解一个为nil的optional值,就有一次crash的可能。

综上,我们需要通过安全的手段去消除这些不必要的“ ?!”
--conditional binding
--guard
用例子来说话吧:
==例子:==conditional binding,value为optional value,使用confitional binding后若value为nil,if代码块不执行,若value非nil,我们得到的nonNilValue(非optional)为value真正的内容,也就是说我们现在使用的value(nonNilValue)在使用时不需要注明"?"或者"!"

1
2
3
4
5
6
for key in allKeys {
    let value = parameterDictionary.objectForKey(key) as? String
    if let nonNilValue = value {
        //do something
    }
}

==例子:==guard,上面例子是针对某代码块中因不同情况而决定是否需要执行的代码块处理,而针对发生某种情况,则跳过整个方法的处理如下:

1
2
3
4
5
6
static private func addTimestampAndSign(dict: NSDictionary?) -> NSDictionary {
        guard dict != nil else {
            return [:]
        }
        //do something  
}

若dict为nil,执行guard代码块return一个空字典, dict非nil(符合期望),do something
--------多个条件语句使用"&&" 分隔

==例子:==guard let, data为optional value ,若data为nil,执行guard代码块(return nil),若data为有效值,则赋值给nonNilData(非optional value),继续执行且nonNilData不再需要" ?!"

1
2
3
4
5
6
7
8
9
10
11
12
13
class private func dataToDictionary(data: NSData?) -> NSDictionary? {
    guard let nonNilData = data else {
        return nil
    }
   
    var resultDict: NSDictionary?
    do {
        resultDict = try NSJSONSerialization.JSONObjectWithData(nonNilData, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
    } catch {
        debugPrint("JSONObjectWithDataError: \(error)")
    }
    return resultDict
}

--------多个guard let语句使用逗号分隔:

1
guard let nonNilName = name, let nonNilPassword = password else {  }

==例子:==if let 还可以用来判断类型转换是否成功返回有效值(非nil)

1
2
3
if let goodsList = dataList.objectForKey("goods_list") as? NSArray {
    //do something
}

==例子:==这里showSuccessAlert返回的是一个option值,若非nil,着执行if中代码块

1
2
3
if let validateAlert = ValidateAlertView.showSuccessAlert(self, status: true, dataList: dataList) {
    // do something
}