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 的一项强大功能,它允许我们以简洁高效的方式处理异步代码。使用可选可逃逸闭包,我们可以将函数作为参数传递给其他函数并在稍后执行它们,即使在调用函数返回后也是如此。这使得编写既易读又易于维护的异步代码变得容易。

可选可逃逸闭包可用于各种场景,例如网络请求、动画和用户界面更新。通过使用可选可逃逸闭包,我们可以编写既高效又响应迅速的代码,而不会牺牲可读性或可维护性。

更新于: 2023年5月4日

1K+ 浏览量

启动您的 职业生涯

通过完成课程获得认证

开始学习
广告