Swift 可逃逸闭包参数
在 Swift 中,可逃逸闭包参数是指可以在其传递到的函数返回后执行的闭包。在这篇文章中,我们将通过示例了解如何创建可逃逸闭包作为参数。
要声明一个可逃逸闭包参数,您需要在函数的参数列表中,闭包类型之前添加 @escaping 关键字。
语法
以下是语法。
func doSomething(completion: @escaping () -> Void) { // Write code here }
在上面的代码中,completion 是一个可选的可逃逸闭包参数,它不接受任何参数并返回 Void。
@escaping 关键字表示闭包可能在 doSomething 函数返回后执行,这意味着闭包会被存储以供将来执行。这在闭包用于异步操作(如网络请求或动画)的场景中非常有用。
请注意,如果您将闭包传递给具有可选可逃逸闭包参数的函数,则需要使用 self. 前缀在闭包内部引用属性或方法时明确指示允许闭包逃逸。这是因为闭包可能在函数返回后执行,因此闭包需要捕获对 self 的强引用以确保引用的属性或方法保持有效。
以下是一个演示如何在 Swift 中使用可选可逃逸闭包的示例
步骤 1 − 在此步骤中,NetworkManager 类有一个名为 fetchDataFromServer 的函数,该函数接受一个名为 completionHandler 的可选可逃逸闭包参数。此闭包以字符串数组作为参数并返回 Void。
class NetworkManager { func fetchDataFromServer(completionHandler: @escaping ([String]) -> Void) { DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 2) { let data = ["John", "Sarah", "Jane"] completionHandler(data) } } }
在 fetchDataFromServer 内部,闭包会被存储以供稍后执行,并在 2 秒延迟后异步执行。然后将数据作为参数传递给闭包。
步骤 2 − 在 TestController 中,dataArray 属性会使用从闭包接收到的数据进行更新,然后在主线程上使用新数据更新 UI。
请注意,我们使用 [weak self] 捕获列表来避免 TestController 和闭包之间的强引用循环。这是因为闭包是异步执行的,如果 TestController 在闭包执行之前被释放,闭包仍然会持有对 TestController 的强引用并阻止其释放。
示例
class TestController: UIViewController { private lazy var clickButton: UIButton = { let button = UIButton() button.addTarget(self, action: #selector(handleButtonClick), for: .touchUpInside) button.backgroundColor = .darkGray button.setTitle("Fetch Data", for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.systemFont(ofSize: 18, weight: .semibold) button.layer.cornerRadius = 5 button.translatesAutoresizingMaskIntoConstraints = false return button }() var networkManager = NetworkManager() var dataArray: [String] = [] override func viewDidLoad() { super.viewDidLoad() initialSetup() } private func initialSetup() { view.backgroundColor = .white navigationItem.title = "Escaping Closure" view.addSubview(clickButton) clickButton.widthAnchor.constraint(equalToConstant: 200).isActive = true clickButton.heightAnchor.constraint(equalToConstant: 50).isActive = true clickButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true clickButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true } @objc private func handleButtonClick() { } }
输出
步骤 3 − 通过调用 fetchDataFromServer() 方法完成 handleButtonClick() 的实现。代码如下 −
示例
@objc private func handleButtonClick() { networkManager.fetchDataFromServer { [weak self] data in self?.dataArray = data DispatchQueue.main.async { print("Data fetched: \(data)") self?.clickButton.setTitle("Data Fetched", for: .normal) } } }
输出
Data fetched: ["John", "Sarah", "Jane"]
在上面的示例中,我们定义了一个 NetworkManager 类,其中包含一个名为 fetchDataFromServer 的函数,该函数接受一个名为 completionHandler 的可选可逃逸闭包参数。在 fetchDataFromServer 内部,我们使用 DispatchQueue.global.asyncAfter 模拟 2 秒的延迟,然后将一些数据(字符串数组)作为参数传递给闭包。
程序运行时,我们等待 2 秒,然后执行传递给 fetchDataFromServer 的闭包。此闭包使用接收到的数据更新 dataArray 属性,然后更新 UI。
另一个示例
此示例演示如何在 Swift 中使用可选可逃逸闭包 −
class MyData { var data = [1, 2, 3, 4, 5] func fetchData(completion: @escaping ([Int]) -> Void) { DispatchQueue.main.asyncAfter(deadline: .now() + 1) { completion(self.data) } } } let myData = MyData() myData.fetchData { (data) in print("Data received: \(data)") } print("Waiting for data...")
输出
Waiting for data... Data received: [1, 2, 3, 4, 5]
在上面的代码中,我们定义了一个 MyData 类,其中包含一个名为 fetchData 的函数,该函数接受一个名为 completion 的可选可逃逸闭包参数。在 fetchData 内部,我们使用 DispatchQueue.main.asyncAfter 模拟 1 秒的延迟,然后将数据数组作为参数传递给闭包。
程序运行时,首先打印“等待数据...”然后等待 1 秒,再执行传递给 fetchData 的闭包。此闭包将“接收到的数据:[1, 2, 3, 4, 5]”打印到控制台。
结论
总之,可选可逃逸闭包是 Swift 的一项强大功能,它允许我们以简洁高效的方式处理异步代码。使用可选可逃逸闭包,我们可以将函数作为参数传递给其他函数并在稍后执行它们,即使在调用函数返回后也是如此。这使得编写既易读又易于维护的异步代码变得容易。
可选可逃逸闭包可用于各种场景,例如网络请求、动画和用户界面更新。通过使用可选可逃逸闭包,我们可以编写既高效又响应迅速的代码,而不会牺牲可读性或可维护性。