转载

想一下再用 guard

自从知道了 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 值为 nildoSomething() 将不会被执行。我们一开始可能仅仅是希望无法获取网速数值的时候,不在控制台打印相应信息,但现在整个 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->VoidsaveInBackground 本身不受影响,如果 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 关键字的时候多思考一下,以免犯下低级错误。

原文  http://kyxu.tech/2016/07/18/想一下再用-guard/
正文到此结束
Loading...