自从知道了 guard let
这种写法之后,我就几乎换掉了所有 if let
写法。但今天要提醒一下,使用 guard let
之前,需要先思考一下,因为这并不总是万全的解放方案。
// bad func createMan0(name: String?, country: String?, age: Int?) -> Man? { if let name = name { if let country = country { if let age = age { return Man(name: name, country: country, age: age) } } } return nil } // good func createMan1(name: String?, country: String?, age: Int?) -> Man? { guard let name = name else { return nil } guard let country = country else { return nil } guard let age = age else { return nil } return Man(name: name, country: country, age: age) }
如上的代码是很常见的 guard let
使用场景,为了避免让我们写出 “Swift 鞭尸金字塔”。
enum NetworkState { case Cellular case Wifi } func test(state:NetworkState) { switch state { case .Cellular: guard let speed = networkSpeed else {return} print("Cellular Speed: /(speed)") case .Wifi: guard let speed = networkSpeed else {return} print("Wifi Speed: /(speed)") } // 可能无法被执行 doSomething() } test(.Cellular)
但这种情况下,如果我们一看到 networkSpeed
是可选型的,就决定使用 guard … else {return}
语法,那么会出现的结果就是一旦 networkSpeed
值为 nil
, doSomething()
将不会被执行。我们一开始可能仅仅是希望无法获取网速数值的时候,不在控制台打印相应信息,但现在整个 test()
都被提前退出了。解决这个问题很简单,把 guard … else {return}
改成 guard … else {break}
,让 switch - case
里面的代码段提前退出就可以了。
但是并不一定每种情况我们都要回避使用 guard … else {return}
enum File { case Pages case Keynote } func saveInBackground( completion: File->Void ) { completion(.Pages) } func closureTest() { saveInBackground( { file in switch file { case .Pages: guard let name = fileName else {return} print("Pages: /(name)") case .Keynote: guard let name = fileName else {return} print("Keynote: /(name)") } }) // 一定会被执行 doSomething() } closureTest()
这种情况下, return
所退出的方法是 saveInBackground
函数里面的闭包 completion: File->Void
, saveInBackground
本身不受影响,如果 saveInBackground
里面还有其他参数是闭包,那么其他闭包自然也不受影响。
func configureButton(button:UIButton, buttonTitle:String?, buttonImage:UIImage?) { if let title = buttonTitle { button.setTitle(title, forState: .Normal) } if let image = buttonImage { button.setImage(image, forState: .Normal) } }
而在这种情况, if let
语法就很自然,有 title 我们就设置 title,有 image 我们就设置 image,没有就算了,总不能说没有 title 或 image 就直接放弃当前的方法,或许我们后面还要做很多其他事情。
希望大家在使用 guard
关键字的时候多思考一下,以免犯下低级错误。