Swift 可选的逃逸闭包参数

swiftserver side programmingprogramming更新于 2025/9/22 13:37:17

在 Swift 中,可选的逃逸闭包参数是指在传递给它的函数返回后可以执行的闭包。在本文中,我们将通过示例了解如何创建逃逸闭包作为参数。

要声明可选的逃逸闭包参数,请在函数参数列表中的闭包类型前添加 @escaping 关键字。

语法

语法如下。

func doSomething(completion: @escaping () -> Void) {
    // 在此处编写代码
}

在上面的代码中,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 秒的延迟,然后将数据数组作为参数传递给闭包。

程序运行时,它首先打印"Waiting for data...",然后等待 1 秒,再执行传递给 fetchData 的闭包。该闭包将"Data received: [1, 2, 3, 4, 5]"打印到控制台。

结论

总而言之,可选转义闭包是 Swift 的一个强大功能,它使我们能够以简洁高效的方式处理异步代码。使用可选转义闭包,我们可以将函数作为参数传递给其他函数,并在稍后执行它们,即使在调用函数返回之后也是如此。这使得编写兼具可读性和可维护性的异步代码变得容易。

可选转义闭包可用于各种场景,例如网络请求、动画和用户界面更新。通过使用可选转义闭包,我们可以编写兼具高性能和响应能力的代码,而不会牺牲可读性和可维护性。



相关文章



关于我们 | 隐私条款 | 学习路线
返回顶部