HoRain云--Swift闭包全解析:从入门到精通
闭包是 Swift 中强大且灵活的功能,类似于匿名函数或 Lambda 表达式。闭包是 Swift 中函数式编程的核心,合理使用可以使代码更简洁、灵活和强大。❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!当闭包是函数的最后一个参数时,可以写成尾随闭包。闭包可以捕获和存储其所在上下文中的常量和变量。自动闭包自动将表达式包装成闭包,延迟求值。:避免闭包过长,复杂的逻辑应提取为单独函数。

🎬 HoRain 云小助手:个人主页
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
目录

Swift 闭包详解
闭包是 Swift 中强大且灵活的功能,类似于匿名函数或 Lambda 表达式。
1. 闭包的基本概念
闭包表达式语法
{ (parameters) -> returnType in
statements
}
简单示例
// 完整写法
let greet = { (name: String) -> String in
return "Hello, \(name)!"
}
print(greet("Alice")) // Hello, Alice!
// 简化写法
let greetShort: (String) -> String = { name in
"Hello, \(name)!"
}
2. 闭包的简化语法
示例:排序数组
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
// 原始写法
let sorted1 = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
// 类型推断
let sorted2 = names.sorted(by: { s1, s2 in return s1 > s2 })
// 隐式返回(单表达式)
let sorted3 = names.sorted(by: { s1, s2 in s1 > s2 })
// 简写参数名
let sorted4 = names.sorted(by: { $0 > $1 })
// 运算符方法
let sorted5 = names.sorted(by: >)
// 尾随闭包
let sorted6 = names.sorted { $0 > $1 }
3. 尾随闭包
当闭包是函数的最后一个参数时,可以写成尾随闭包。
// 标准写法
func loadData(completion: (String) -> Void) {
completion("Data loaded")
}
loadData(completion: { data in
print(data)
})
// 尾随闭包写法
loadData { data in
print(data)
}
// 多个参数,最后一个闭包
func fetchData(id: Int, completion: (String) -> Void) {
completion("Data for \(id)")
}
fetchData(id: 1) { data in
print(data)
}
4. 闭包捕获值
闭包可以捕获和存储其所在上下文中的常量和变量。
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
// 闭包捕获了 runningTotal 和 amount
let incrementer: () -> Int = {
runningTotal += amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen() // 返回 10
incrementByTen() // 返回 20
incrementByTen() // 返回 30
let incrementByFive = makeIncrementer(forIncrement: 5)
incrementByFive() // 返回 5
incrementByFive() // 返回 10
5. 闭包类型
闭包作为函数参数
func travel(action: (String) -> Void) {
print("I'm getting ready to go.")
action("London")
print("I arrived!")
}
// 使用
travel { (place: String) in
print("I'm going to \(place)")
}
闭包作为返回值
func createTravel() -> (String) -> Void {
var counter = 1
return { destination in
print("\(counter). I'm going to \(destination)")
counter += 1
}
}
let travel = createTravel()
travel("Paris") // 1. I'm going to Paris
travel("Tokyo") // 2. I'm going to Tokyo
闭包作为属性
class DataManager {
var onDataLoaded: ((String) -> Void)?
func loadData() {
// 模拟异步加载
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.onDataLoaded?("Data loaded successfully")
}
}
}
let manager = DataManager()
manager.onDataLoaded = { message in
print(message)
}
manager.loadData()
6. 逃逸闭包和非逃逸闭包
非逃逸闭包(默认)
func processNumbers(numbers: [Int], transform: (Int) -> Int) -> [Int] {
return numbers.map(transform)
}
// 闭包在函数返回前就执行完了
let result = processNumbers(numbers: [1, 2, 3]) { $0 * 2 }
逃逸闭包
闭包在函数返回后被执行,需要使用 @escaping标注。
class DataLoader {
var completionHandlers: [() -> Void] = []
func loadData(completion: @escaping () -> Void) {
// 存储闭包,稍后执行
completionHandlers.append(completion)
}
func executeCompletions() {
for handler in completionHandlers {
handler()
}
completionHandlers.removeAll()
}
}
使用逃逸闭包的场景
func fetchData(completion: @escaping (String) -> Void) {
// 模拟异步网络请求
DispatchQueue.global().async {
// 模拟网络延迟
Thread.sleep(forTimeInterval: 2)
DispatchQueue.main.async {
completion("Data received")
}
}
}
fetchData { data in
print(data) // 2秒后打印
}
7. 自动闭包
自动闭包自动将表达式包装成闭包,延迟求值。
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count) // 5
// 创建一个自动闭包
let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count) // 5(还未执行)
print(customerProvider()) // Chris
print(customersInLine.count) // 4
// 使用 @autoclosure
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0)) // Alex
8. 闭包中的内存管理
循环引用问题
class MyClass {
var value = 0
var closure: (() -> Void)?
func setupClosure() {
// 强引用循环
closure = {
self.value += 1 // 闭包捕获了self
}
}
deinit {
print("MyClass deinitialized")
}
}
// 测试
var obj: MyClass? = MyClass()
obj?.setupClosure()
obj = nil // 不会打印 "deinitialized",内存泄漏!
解决方案:捕获列表
class MyClass {
var value = 0
var closure: (() -> Void)?
func setupClosure() {
// 1. 弱引用
closure = { [weak self] in
guard let self = self else { return }
self.value += 1
}
// 2. 无主引用(适用于确定不会为nil的情况)
// closure = { [unowned self] in
// self.value += 1
// }
// 3. 捕获特定属性
closure = { [self] in
value += 1
}
}
deinit {
print("MyClass deinitialized")
}
}
9. 高级闭包用法
函数柯里化
func addNumbers(_ a: Int) -> (Int) -> Int {
return { b in
return a + b
}
}
let addFive = addNumbers(5)
print(addFive(3)) // 8
print(addFive(10)) // 15
闭包作为类型别名
typealias CompletionHandler = (Result<String, Error>) -> Void
typealias Transformer<T> = (T) -> T
func process<T>(value: T, transform: Transformer<T>) -> T {
return transform(value)
}
let result = process(value: 5) { $0 * 2 } // 10
闭包组合
func compose<A, B, C>(
_ f: @escaping (A) -> B,
_ g: @escaping (B) -> C
) -> (A) -> C {
return { a in
g(f(a))
}
}
let addTwo = { $0 + 2 }
let multiplyByThree = { $0 * 3 }
let addThenMultiply = compose(addTwo, multiplyByThree)
print(addThenMultiply(5)) // 21
10. 实际应用示例
网络请求
func fetchData(from url: String, completion: @escaping (Result<Data, Error>) -> Void) {
guard let url = URL(string: url) else {
completion(.failure(NSError(domain: "Invalid URL", code: 400)))
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
guard let data = data else {
completion(.failure(NSError(domain: "No data", code: 404)))
return
}
completion(.success(data))
}.resume()
}
动画
UIView.animate(withDuration: 0.3, animations: {
// 动画代码
}) { finished in
// 动画完成后的回调
if finished {
print("Animation completed")
}
}
高阶函数
let numbers = [1, 2, 3, 4, 5]
// map
let doubled = numbers.map { $0 * 2 } // [2, 4, 6, 8, 10]
// filter
let evens = numbers.filter { $0 % 2 == 0 } // [2, 4]
// reduce
let sum = numbers.reduce(0) { $0 + $1 } // 15
// sorted
let sorted = numbers.sorted { $0 > $1 } // [5, 4, 3, 2, 1]
// forEach
numbers.forEach { print($0) }
最佳实践
-
简化语法:在可能的情况下使用简写参数名
-
避免循环引用:使用
[weak self]或[unowned self] -
适当逃逸:只在需要时使用
@escaping -
保持简洁:避免闭包过长,复杂的逻辑应提取为单独函数
-
类型安全:利用 Swift 的类型推断,但也要保持可读性
-
错误处理:在异步闭包中妥善处理错误
-
性能考虑:避免在闭包中创建不必要的对象
闭包是 Swift 中函数式编程的核心,合理使用可以使代码更简洁、灵活和强大。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙
更多推荐


所有评论(0)