目录
1. guard 关键字介绍
在Swift里,有三种类型的语句:简单语句,编译控制语句和控制流语句。简单语句用于构造表达式和声明,编译控制语句用于更改编译器的行为,控制流语句用于控制程序的执行顺序。控制流语句又包含了:循环语句(for
, for in
, while
, repeat while
),分支语句(switch
, if
, guard
)和控制转移语句(break
, continue
, fallthrough
, return
, throw
, defer
等)。在分支语句里, if表示条件通过则执行,而guard 结合else表示条件通不过则执行。同样的逻辑,后者可以大大提高代码的可读性。swift官方文档对于guard的定义如下:
A guard statement is used to transfer program control out of a scope if one or more conditions aren’t met.
一个guard 的语句有如下格式:
1
2
3
guard condition else{
statements
}
2. guard 的应用场景
我们来看看guard的几个应用场景,以下面歌曲Song类举例:
1
2
3
4
5
class Song {
var name:String?
var singer: String?
var age: Double?
}
该Song类有三个可选值实例属性,分别是name
, singer
, age
, 默认值均为nil。我们有一个打印其信息的函数
1
2
3
4
5
6
7
func printInfo0(){
if let tempName = self.name {
print("name: \(tempName)")
return
}
print("name is nil")
}
在printInfo0()
中,我们用Optional Binding先判断self.name
是否有值,若有,则打印;否则,打印nil。我们将主要业务逻辑包裹在判断语句中。下面我们用guard来实现相同的逻辑。
1
2
3
4
5
6
7
func printInfo1(){
guard let tempName = self.name else{
print("name is nill")
return
}
print("name: \(tempName)")
}
在printInfo1()
中,我们同样用Optional Binding判断self.name
是否有值, 将其没有的情况else
先处理。然后在下面处理我们的主要业务逻辑 print("name: \(tempName)")
, 这时候的tempName
已经拆包,可以直接用,与if let
中的tempName
类似。guard
在这里就像一个卫士一样,将我们不要的情况先处理,然后在余下函数主体中处理主要业务逻辑。代码可读性的提高,在这个例子中不明显,我们再来看下面这个例子体会一下。
2.1 guard 应用场景:多条件分别判断
同样是上面的Song类,我们改写其printInfo0()
方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func printInfo0(){
if let tempName = self.name {
print("name: \(tempName)")
if let tempSinger = self.singer{
print("singer: \(tempSinger)")
if let tempAge = self.age{
print("age: \(tempAge)")
return
}
print("age is nil")
return
}
print("singer is nil")
return
}
print("name is nil")
}
同样的逻辑,我们判断三次,如果歌曲有名字,则打印;如果有歌手,则打印;如果有年龄,则打印。否则返回。是不是读起来not feel the right, there must be a better way to do it。 下面我们用guard改写:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func printInfo1(){
guard let tempName = self.name else{
print("name is nill")
return
}
print("name: \(tempName)")
guard let tempSinger = self.singer else{
print("singer is nil")
return
}
print("singer: \(tempSinger)")
guard let tempAge = self.age else{
print("age is nil")
return
}
print("age: \(tempAge)")
}
先处理没有名字的情况,然后处理有名字;接着再处理没有歌手的情况,然后处理有歌手; 接着是年龄,也一样。是不是感觉读起来顺畅多了。
2.2 guard 应用场景:多条件同时判断
或者有时候你不需要对每个条件的失败情况进行处理,你需要的是统一处理失败情况,统一处理业务逻辑。例如用if let
改写 printInfo0()
1
2
3
4
5
6
7
8
9
10
11
func printInfo0(){
if let tempName = self.name,
let tempSinger = self.singer,
let tempAge = self.age{
print("name: \(tempName)")
print("singer: \(tempSinger)")
print("age: \(tempAge)")
return
}
print("information is not complete")
}
当name
, singer
, age
都有值时,打印。否则打印”information is not complete”。用guard
实现 printInfo1()
如下:
1
2
3
4
5
6
7
8
9
10
11
func printInfo1(){
guard let tempName = self.name,
let tempSinger = self.singer,
let tempAge = self.age else{
print("information is not complete")
return
}
print("name: \(tempName)")
print("singer: \(tempSinger)")
print("age: \(tempAge)")
}
这样将不符合条件的先处理,然后再处理符合条件的主要业务逻辑,代码更清晰易读。
2.3 guard 应用场景:for 循环
guard else 还有一点需要注意的是必须要转移控制,用break
,continue
, 或者return
。比如
我们想打印[1, nil, 3, 4, 5]
中每一个元素,nil 打印为 nil
1
2
3
4
5
6
7
8
9
10
let possibleNumbers: [Int?] = [1,nil,3,4,5]
for number in possibleNumbers{
guard let n = number else{
print("nil")
break
}
print(n)
}
//输出: 1, nil
这里用break
打印 “1, nil”不是我们想要的结果,应该用continue
,如下
1
2
3
4
5
6
7
8
9
10
let possibleNumbers: [Int?] = [1,nil,3,4,5]
for number in possibleNumbers{
guard let n = number else{
print("nil")
continue
}
print(n)
}
//输出: 1, nil, 3, 4, 5
因此在用guard
时,应该合理选择 break
,continue
, 或者return
3 总结
guard关键字对于if 相当于一个补集,先处理不需要的情况,再集中精力处理主要业务逻辑,对于提高代码的可读性和修改性起到不小作用。以上三个应用场景归纳起来都是对于guard else的这个特性的应用。在内存管理时的weak-strong dance 里我们也可以用guard先处理nil的情况,这里就不再举例了。希望读者以后可以熟练运用guard关键字。