Swift 学习笔记:逃逸闭包

在 Swift 中,闭包是一种自包含的函数代码块,可以在代码中被传递和使用。闭包可以捕获和存储其所在上下文中任何常量和变量的引用。这就是所谓的闭包的"闭合性"。

什么是逃逸闭包?

在 Swift 中,当一个闭包作为参数传递给一个函数,并且这个闭包在函数返回之后才被调用,我们称这个闭包为逃逸闭包。换句话说,逃逸闭包是在函数执行完毕后仍然可以在函数外部被调用的闭包。

在 Swift 中,可以使用 @escaping 关键字来标记逃逸闭包参数。

swift 复制代码
func someFunctionWithEscapingClosure(completion: @escaping () -> Void) {
    // 在函数执行完毕后,闭包仍然可以在函数外部被调用
}

为什么需要逃逸闭包?

逃逸闭包主要用于异步操作,比如网络请求、定时器等。在这些情况下,我们需要在函数执行完毕后继续使用这个闭包,比如在网络请求返回数据后更新 UI,或者在定时器触发后执行一些操作。

逃逸闭包的使用

下面是一个逃逸闭包的简单例子:

swift 复制代码
var completionHandlers: [() -> Void] = []

func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}

func doSomething() {
    someFunctionWithEscapingClosure { 
        print("Hello, world!")
    }
}

doSomething()

在这个例子中,someFunctionWithEscapingClosure 函数接受一个逃逸闭包作为参数,并将这个闭包添加到 completionHandlers 数组中。然后在 doSomething 函数中调用 someFunctionWithEscapingClosure,并传入一个打印 "Hello, world!" 的闭包。这个闭包在 doSomething 函数执行完毕后仍然可以被调用。

逃逸闭包在网络请求中的应用

在网络请求中,逃逸闭包的使用非常常见。下面是一个简单的示例,展示了如何在网络请求完成后使用逃逸闭包处理返回的数据:

swift 复制代码
import Foundation

// 定义一个网络请求函数,接受一个逃逸闭包作为参数
func fetchData(completion: @escaping (Data?, Error?) -> Void) {
    let url = URL(string: "https://example.com/data")!

    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        // 当网络请求完成时,调用逃逸闭包
        completion(data, error)
    }

    task.resume()
}

// 调用网络请求函数
fetchData { (data, error) in
    if let error = error {
        print("Failed to fetch data: \(error)")
    } else if let data = data {
        print("Data fetched: \(data)")
    }
}

在这个示例中,fetchData 函数接受一个逃逸闭包作为参数。这个闭包接受两个参数:一个是网络请求返回的数据,另一个是可能出现的错误。当网络请求完成时,这个闭包被调用,以处理返回的数据或错误。

这就是逃逸闭包在网络请求中的一个典型应用。通过使用逃逸闭包,我们可以在网络请求完成后异步处理返回的数据,而不需要阻塞当前的执行流程。

逃逸闭包在定时器中的应用

在 Swift 中,定时器(Timer)也常常与逃逸闭包一起使用。下面是一个简单的示例,展示了如何在定时器触发时使用逃逸闭包执行一些操作:

swift 复制代码
import Foundation

// 定义一个启动定时器的函数,接受一个逃逸闭包作为参数
func startTimer(withInterval interval: TimeInterval, action: @escaping () -> Void) {
    Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in
        // 当定时器触发时,调用逃逸闭包
        action()
    }
}

// 调用启动定时器的函数
startTimer(withInterval: 1.0) {
    print("Timer triggered!")
}

在这个示例中,startTimer 函数接受一个逃逸闭包作为参数。当定时器每次触发时,这个闭包就会被调用。

这就是逃逸闭包在定时器中的一个典型应用。通过使用逃逸闭包,我们可以在定时器触发时异步执行一些操作,而不需要阻塞当前的执行流程。

逃逸闭包与回调函数

在 Swift 中,逃逸闭包经常被用作回调函数。回调函数是一种在特定事件发生时被调用的函数,它允许我们将一些代码的执行延迟到需要的时候。

逃逸闭包作为回调函数的一个主要特点是它可以"逃逸"出当前的函数或方法。这意味着闭包可以在其父函数返回后的某个时间点被调用,而不是立即在其父函数中被调用。这对于处理异步操作(如网络请求、定时器等)非常有用,因为这些操作通常需要在未来的某个时间点完成。

逃逸闭包与高阶函数

在 Swift 中,高阶函数是接受其他函数作为参数或返回其他函数的函数。逃逸闭包在高阶函数中的应用非常广泛,因为它们可以在函数执行完毕后仍然被调用。

下面是一个使用逃逸闭包的高阶函数示例:

swift 复制代码
func performOperation(_ operation: @escaping (Int) -> Int, on number: Int) -> () -> Int {
    return {
        return operation(number)
    }
}

let doubleOperation = performOperation({ $0 * 2 }, on: 5)

print(doubleOperation()) // 输出 10

在这个示例中,performOperation 是一个高阶函数,它接受一个逃逸闭包和一个整数作为参数,并返回一个新的闭包。这个新的闭包在被调用时会执行传入的逃逸闭包,并将结果返回。

这就是逃逸闭包在高阶函数中的一个典型应用。通过使用逃逸闭包,我们可以在高阶函数中创建和返回新的闭包,这些闭包可以在函数执行完毕后仍然被调用。

总结

逃逸闭包是 Swift 中处理异步操作和回调的重要概念之一。理解和掌握逃逸闭包的使用,可以帮助我们更好地编写异步和回调代码。

相关推荐
大熊猫侯佩1 天前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(三)
数据库·swiftui·swift
大熊猫侯佩1 天前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(二)
数据库·swiftui·swift
大熊猫侯佩1 天前
用异步序列优雅的监听 SwiftData 2.0 中历史追踪记录(History Trace)的变化
数据库·swiftui·swift
大熊猫侯佩1 天前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(一)
数据库·swiftui·swift
season_zhu2 天前
iOS开发:关于日志框架
ios·架构·swift
大熊猫侯佩2 天前
SwiftUI 中如何花样玩转 SF Symbols 符号动画和过渡特效
swiftui·swift·apple
大熊猫侯佩2 天前
SwiftData 共享数据库在 App 中的改变无法被 Widgets 感知的原因和解决
swiftui·swift·apple
大熊猫侯佩2 天前
使用令牌(Token)进一步优化 SwiftData 2.0 中历史记录追踪(History Trace)的使用
数据库·swift·apple
大熊猫侯佩2 天前
SwiftUI 在 iOS 18 中的 ForEach 点击手势逻辑发生改变的解决
swiftui·swift·apple