自从知道了 <code>guard let</code> 这种写法之后,我就几乎换掉了所有 <code>if let</code> 写法。但今天要提醒一下,使用 <code>guard let</code> 之前,需要先思考一下,因为这并不总是万全的解放方案。
// 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)
}
如上的代码是很常见的 <code>guard let</code> 使用场景,为了避免让我们写出 “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)
但这种情况下,如果我们一看到 <code>networkSpeed</code> 是可选型的,就决定使用 <code>guard ... else {return}</code> 语法,那么会出现的结果就是一旦 <code>networkSpeed</code> 值为 <code>nil</code> , <code>doSomething()</code> 将不会被执行。我们一开始可能仅仅是希望无法获取网速数值的时候,不在控制台打印相应信息,但现在整个 <code>test()</code> 都被提前退出了。解决这个问题很简单,把 <code>guard ... else {return}</code> 改成 <code>guard ... else {break}</code>,让 <code>switch - case</code> 里面的代码段提前退出就可以了。
但是并不一定每种情况我们都要回避使用 <code>guard ... else {return}</code>
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()
这种情况下,<code>return</code> 所退出的方法是 <code>saveInBackground</code> 函数里面的闭包 <code>completion: File->Void</code>,<code>saveInBackground</code> 本身不受影响,如果 <code>saveInBackground</code> 里面还有其他参数是闭包,那么其他闭包自然也不受影响。
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)
}
}
而在这种情况,<code>if let</code> 语法就很自然,有 title 我们就设置 title,有 image 我们就设置 image,没有就算了,总不能说没有 title 或 image 就直接放弃当前的方法,或许我们后面还要做很多其他事情。
没东西了
希望大家在使用 <code>guard</code> 关键字的时候多思考一下,以免犯下低级错误。