这几天都没睡好,前天电脑黑屏开不开机了,工作内容都在上面。都快疯了。熬夜也没修复上,硬盘插在主板上也不好使,抱着试试看的态度买了根SATA转USB的线,没想到竟然读盘了,感动。(我曾一度以为我要一朝回到解放前了)。

“能量和毅力征服了一切”

尾随闭包语法接受参数

上一次我们使用了一个闭包语法:

1
2
3
4
5
6
7
8
9
func tellmeadr(action: () -> Void){
print("Are you Ready?")
action()
print("Let's go!")
}

tellmeadr {
print("hello!zhhooo!~")
}

() -> Void表示着不接受任何参数也不返回任何数据,在尾随式闭包中调用参数与在从闭包中调用参数格式相同,例如:

1
2
3
4
5
6
7
8
9
10
func tellmeadr(action: (String) -> Void){
print("Are you Ready?")
action("zhhooo.com")
print("Let's go!")
}

tellmeadr {(url: String) in
print("hello!zhhooo!~\(url)")
}

zhhooo.com从函数中一直传递到闭包运行。

其他例子:

1
2
3
4
5
6
7
8
9
10
11
12
func makePizza(addToppings: (Int) -> Void ) {
print("The dough is ready.")
print("The base is flat.")
addToppings(3)
}
makePizza { (toppingCount: Int) in
let toppings = ["ham", "salami", "onions", "peppers"]
for i in 0..<toppingCount {
let topping = toppings[i]
print("I'm adding \(topping)")
}
}

其他例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func getDirections(to destination: String, then travel: ([String]) -> Void) {
let directions = [
"Go straight ahead",
"Turn left onto Station Road",
"Turn right onto High Street",
"You have arrived at \(destination)"
]
travel(directions)
}
getDirections(to: "London") { (directions: [String]) in
print("I'm getting my car.")
for direction in directions {
print(direction)
}
}

尾随闭包语法返回值

与闭包相同,我们虽然一直在用Void,当我们将Void换成类型时,比如String,配合return就可以让闭包返回值了,例如:

1
2
3
4
5
6
7
8
9
func zhhooo(url:(String) -> String){
print("Let's go!")
let adr = url("zhhooo.com")
print("Let's go to the \(adr)")
}

zhhooo{(url:String) in
return "https://\(url)/"
}

其他例子:

1
2
3
4
5
6
7
8
9
func encrypt(password: String, using algorithm: (String) -> String) {
print("Encrypting password...")
let result = algorithm(password)
print("The result is \(result)")
}
encrypt(password: "t4ylor") { (password: String) in
print("Using top secret encryption!")
return "SECRET" + password + "SECRET"
}

简化代码及速记参数

在Swift中你可以简化你的代码,例如:

1
2
3
4
5
func zhhooo(url:(String) -> String){
print("Let's go!")
let adr = url("zhhooo.com")
print("Let's go to the \(adr)")
}

这个刚才举的例子。在我们调用的时候,我们正常应该输入:

1
2
3
zhhooo{(url:String) -> String in
return "https://\(url)/"
}

因为Swift知道,输入的值必须是字符串,所以可以简化为:

1
2
3
zhhooo{url -> String in
return "https://\(url)/"
}

Swift也知道,返回的值必须是字符串,所以可以简化为:

1
2
3
zhhooo{url in
return "https://\(url)/"
}

由于闭包代码只有一行,所以那一行一定是返回的那一行,所以可以简化为:

1
2
3
zhhooo{url in
"https://\(url)/"
}

Swift闭包可以用美元标志提供自动名称,用美元标志命名,从数字0开始计数:

1
2
3
zhhooo{
"https://\($0)/"
}

具有多个参数的闭包

闭包中可以通过速记参数来为闭包添加多个参数,例如我们不仅需要记录网站的网址,还需要网站点赞人数:

1
2
3
4
5
func zhhooo(url:(String,Int) -> String){
print("Let's go!")
let adr = url("zhhooo.com",88)
print("Let's go to the \(adr)")
}

在调用的时候使用速记参数来进行调用:

1
2
3
zhhooo{
"http://\($0)/ 有\($1)人点赞"
}

函数返回一个闭包

是的,函数可以通过字符串的形式返回一个闭包并且能够运行这个闭包。在调用函数时会有两个->,第一个是函数的返回值,函数返回值内的String代表这个返回的闭包需要一个字符串参数(如果这个闭包没有需要的参数可以直接留空func zhhooo() -> () -> Void{),第二个是闭包的返回值。例如:

1
2
3
4
5
6
7
8
func zhhooo() -> (String) -> Void{
return {
print("website:\($0)")
}
}

let txt = zhhooo()
txt("zhhooo.com")

print("website:\($0)")作为一个闭包,用来作为函数的返回值。之后用创建一个叫txt的闭包,闭包内容为函数的返回值,再来运行它。

下面是不建议的用法:

1
2
3
4
5
6
7
func zhhooo() -> (String) -> Void{
return {
print("website:\($0)")
}
}

let txt = zhhooo()("zhhooo.com")

其他例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func createAgeCheck(strict: Bool) -> (Int) -> Bool {
if strict {
return {
if $0 <= 21 {
return true
} else {
return false
}
}
} else {
return {
if $0 <= 18 {
return true
} else {
return false
}
}
}
}
let ageCheck = createAgeCheck(strict: true)
let result = ageCheck(20)
print(result)

捕获值

如果你在闭包内部使用任何外部值,则Swift会捕获它们-将它们存储在闭包旁边,因此即使它们不再存在,也可以对其进行修改。例如:

1
2
3
4
5
6
7
8
func zhhooo() -> (String) -> Void{
return {
print("website:\($0)")
}
}

let txt = zhhooo()
txt("zhhooo.com")

这个时候我们需要记录一下闭包调用的次数:

1
2
3
4
5
6
7
8
9
func zhhooo() -> (String) -> Void{
var num = 0

return {
print("website:\($0)")
num += 1

}
}

即使该num变量是在zhhooo()函数内部创建的,它也会被闭包捕获,因此对于该闭包仍将保持活动状态。

因此,如果我们txt(“zhhooo.com”)多次调用,变量num将不断增加:

1
2
3
4
let txt = zhhooo()
txt("zhhooo.com")
txt("zhhooo.com")
txt("zhhooo.com")

其他例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
func storeTwoValues(value1: String, value2: String) -> (String) -> String {
var previous = value1
var current = value2
return { new in
let removed = previous
previous = current
current = new
return "Removed \(removed)"
}
}
let store = storeTwoValues(value1: "Hello", value2: "World")
let removed = store("Value Three")
print(removed)

总结

  • 你可以为变量分配闭包,然后再调用它们。
  • 闭包可以接受参数和返回值,例如常规函数。
  • 你可以将闭包作为参数传递给函数,并且这些闭包可以具有自己的参数和返回值。
  • 如果函数的最后一个参数是闭包,则可以使用尾随闭包语法。
  • Swift会自动提供诸如$0和的速记参数名称$1,但并非所有人都使用它们。
  • 如果在闭包内部使用外部值,则将捕获它们,以便闭包以后可以引用它们。

参考资料

查看下一天的SwiftUI学习笔记

关于100days英文课程