使用Guard的三个注意
使用 guard ,相比一些以前的写法,这儿有更精简的方式。 分享三个有用的guard技巧,使你的代码更简洁也更容易理解这种方式构建的功能。 当然这不是一个关于一般的编码风格或编码指引,更多的关注guard如何简化代码。
嵌套
代码很简单,一看便懂:
1
2
3
4
5
6
7
8
9
10
11
//无意义的大量代码,显示代码结构如何嵌套看起来混乱
if let a = a() {
let x = b(a)
x.fn()
if let u = x.nxt() {
let ux = u.brm()
if let uxt = ux.nxt() {
perform(uxt)
}
}
}
更简洁的:
1
2
3
4
5
6
7
8
guard let a = a() else { return }
let x = b(a)
x.fn()
guard let u = x.nxt() else { return }
let ux = u.brm()
guard let uxt = ux.nxt() else { return }
perform(uxt)
模式绑定
以上代码如果你使用一个枚举 enum,效果更好。想想我们是如何处理以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protocol NotificationListener {
func handleNotification(notification: Notification)
}
enum Notification {
case UserLoggedIn(user: String, date: NSDate, domain: String)
case FileUploaded(file: String, location: String, size: Int, user: String)
}
struct FileUploadHandler: NotificationListener {
/**
执行通知处理,把上传的文件移动到临时文件夹
*/
func handleNotification(notification: Notification) {
guard case .FileUploaded(let file, let location, _, let user) = notification
else { return }
if user == self.currentUser {
self.moveFile(file, atLocation: location)
}
}
}
在使用guard的情况下实现了2个功能:
1.它确保处理通知仅适用于FileUploaded通知,而不是ISUserLoggedIn通知。
2.它结合了枚举的所有相关值到当前范围,使得我们很容易使用数据。
条件判断
不管怎样,使用guard 我们更能简化例子,像这样:
1
2
3
4
5
6
7
8
9
struct FileUploadHandler: NotificationListener {
func handleNotification(notification: Notification) {
guard case .FileUploaded(let file, let location, _, let user) = notification
where user == self.currentUser
else { return }
self.moveFile(file, atLocation: location)
}
}
并且还可以多个where 并用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Foundation
func confirmPath(pathObject: AnyObject) -> Bool {
guard let url = pathObject as? NSURL,
let components = url.pathComponents
where components.count > 0,
let first = components.dropFirst().first
where first == "Applications",
let last = components.last
where last == "MyApp.app"
else { return false }
print("valid folder", last)
return true
}
print(confirmPath(NSURL(fileURLWithPath: "/Applications/MyApp.app")))
// : valid folder MyApp.app
// : true
嵌套枚举
1
2
3
4
5
6
enum SidebarEntry {
case Headline(String)
case Item(String)
case Seperator
}
定义一个数组:
1
2
3
4
5
6
7
8
9
10
11
12
[.Headline("Global"),
.Item("Dashboard"),
.Item("Popular"),
.Seperator,
.Headline("Me"),
.Item("Pictures"),
.Seperator,
.Headline("Folders"),
.Item("Best Pics 2013"),
.Item("Wedding")
]
每个 Item 都有一个不同事件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
enum Action {
case .Popular
case .Dashboard
case .Pictures
case .Folder(name: String)
}
enum SidebarEntry {
case Headline(String)
case Item(name: String, action: Action)
case Seperator
}
[.Headline("Global"),
.Item(name: "Dashboard", action: .Dashboard),
.Item(name: "Popular", action: .Popular),
.Item(name: "Wedding", action: .Folder("fo-wedding")]
现在我们用guard 试试发布一个文件夹:
1
2
3
4
5
func publishFolder(entry: SidebarEntry) {
guard case .Item(_, .Folder(let name)) = entry
else { return }
Folders.sharedFolders().byName(name).publish()
}
这是一个层次结构比较复杂的模型,但仍然能够匹配,甚至还能匹配更复杂的嵌套类型。
单行返回
当你在else 标签里返回前,希望能够做一些其他的处理:
1
2
3
4
5
6
7
8
9
guard let a = b() else {
print("wrong action")
return
}
// or
guard let a = b() else {
self.completion(items: nil, error: "Could not")
return
}
当你的返回是Void,还可以这样处理:
1
2
3
4
5
guard let a = b() else {return print("wrong action")}
// or
guard let a = b() else {
return self.completion(items: nil, error: "Could not")
}
try? in guards
1
2
3
guard let item = item,
result = try? item.perform()
else { return print("Could not perform") }
综合使用
最后,让 let , case 在一个guard 中使用试试:
1
2
3
4
5
guard let messageids = overview.headers["message-id"],
messageid = messageids.first,
case .MessageId(_, let msgid) = messageid
where msgid == self.originalMessageID
else { return print("Unknown Message-ID:", overview) }