望其项背 iOS - swift: 闭包(闭包的基础,嵌套函数会维护它外部的变量,延迟执行 {} 括起来的闭包逻辑,@escaping)
望其项背 iOS - swift: 闭包(闭包的基础,嵌套函数会维护它外部的变量,延迟执行 {} 括起来的闭包逻辑,@escaping)
示例如下:
SwiftView06.swift
/*
* 本例用于演示闭包(闭包的基础,嵌套函数会维护它外部的变量,延迟执行 {} 括起来的闭包逻辑,@escaping)
*
* 闭包(closure)在 swift 中就是函数的匿名简化版,类似 lambda 表达式
*/
import SwiftUI
struct SwiftView06: View {
var result: String = "";
init() {
result = sample1() // 闭包基础 1
result += "\n";
result += sample2() // 闭包基础 2
result += "\n";
result += sample3() // 嵌套函数会维护它外部的变量(这个就是其他语言的闭包概念,而 swift 中的闭包类似于其他语言的匿名函数)
result += "\n";
result += sample4() // 延迟执行 {} 括起来的闭包逻辑
result += "\n";
result += sample5() // @escaping
}
var body: some View {
VStack {
HStack {
Text(result)
Spacer()
}
Spacer()
}
}
func sample1() -> String {
let a = [3, 1, 5, 4, 2]
let b = a.sorted(by: ascend) // 函数作为参数
let c = a.sorted(by: { (a: Int, b: Int) -> Bool in return a < b }) // 闭包作为参数(这个是写全了的闭包表达式)
let d = a.sorted(by: { a, b in return a < b }) // 简化闭包(省略闭包的参数类型,由编译器推断)
let e = a.sorted(by: { a, b in a < b }) // 再简化闭包(如果闭包是单表达式则可以省略 return)
let f = a.sorted(by: { $0 < $1 }) // 再再简化闭包(可以通过 $0, $1, $2... 来引用闭包的参数,同时省略掉 in)
let g = a.sorted(by: <) // 再再再简化闭包(如果就是 2 个参数通过运算符比较的话,那么只写运算符即可,其他都可以省略)
let h = a.sorted() { $0 < $1 } // 如果闭包作为函数的最后一个参数,则闭包可以放在 () 之外,且不需要参数标签
let i = a.sorted { $0 < $1 } // 如果函数只有闭包一个参数,则可以省略掉 (),且不需要参数标签
return "\(b), \(c), \(d), \(e), \(f), \(g), \(h), \(i)";
}
func ascend(_ a: Int, _ b: Int) -> Bool {
return a < b
}
func sample2() -> String {
// 调用闭包作为参数的函数(用函数的方式,这里可以发现,闭包其实就是函数的匿名简化版)
requestUrl(url: "http://webabcd.cnblogs.com", onSucess: success(message:), onError: error(message:))
// 调用闭包作为参数的函数(用闭包的方式)
requestUrl(url: "http://webabcd.cnblogs.com", onSucess: { message in
print(message)
}, onError: { message in
print(message)
})
// 调用闭包作为参数的函数(闭包可以放在 () 之外,前提是闭包参数的后面不能再有非闭包参数,则该闭包参数可以放到 () 之外)
// 注;放在 () 之外的第一个闭包的参数标签请直接省略
requestUrl(url: "http://webabcd.cnblogs.com") { message in
print(message)
} onError: { message in
print(message)
}
// 通过 $0, $1, $2... 来引用闭包的参数
requestUrl(url: "http://webabcd.cnblogs.com") {
print($0)
} onError: {
print($0)
}
return "";
}
// 闭包作为参数
func requestUrl(url: String, onSucess: (String) -> Void, onError: (String) -> Void) {
if Int64(Date.init().timeIntervalSince1970) % 2 == 0 {
onSucess("成功")
} else {
onError("失败")
}
}
func success(message: String) {
print(message)
}
func error(message: String) {
print(message)
}
func sample3() -> String {
let a = increase(number: 2)
let b = increase(number: 3)
// a 和 b 都是 increase() 中的 myFunc() 函数,它不会丢失其外部的 total 变量
// a 和 b 都是 increase() 中的 myFunc() 函数,但是是不同的对象,他们会分别维护他们外部的 total 变量
print(a(), b()) // 2 3
print(a(), b()) // 4 6
print(a(), b()) // 6 9
return "";
}
func increase(number: Int) -> () -> Int {
var total = 0
func myFunc() -> Int { // 这个函数会将其外部的 total 变量捕获过来,也就是说 myFunc() 是不会丢失 total 的
total += number
return total
}
// 函数返回的函数就是就是其他语言的闭包概念(闭包引用的闭包外的变量的生命周期会拉长到与闭包一致)
// 而 swift 中的闭包类似于其他语言的匿名函数
return myFunc
}
func sample4() -> String {
var a = [1, 2, 3, 4, 5]
// 直接用 {} 括起来的闭包逻辑是不会立即执行的
let b = { a.remove(at: 0) }
print(a) // [1, 2, 3, 4, 5]
// 此时才会调用闭包中的逻辑
b()
print(a) // [2, 3, 4, 5]
return ""
}
var funcList = [() -> Void]()
mutating func sample5() -> String {
appendFunc { print("abc") }
appendFunc { print("xyz") }
// appendFunc() 函数退出了,也能执行传给 appendFunc() 的闭包函数
for item in funcList {
item()
}
return ""
}
// 闭包作为参数时可以指定闭包为 @escaping 类型
// 非 @escaping 类型闭包的生命周期:闭包作为参数传给函数,闭包在函数中执行(执行完后,闭包就死了),退出函数
// @escaping 类型闭包的生命周期:闭包作为参数传给函数,退出函数,闭包还活着
mutating func appendFunc(a: @escaping () -> Void) {
// 这里你如果想函数退出后再执行闭包,则需要将此闭包标记为 @escaping 类型,否则会编译时报错
funcList.append(a)
}
}