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 的一項強大功能,它允許我們以簡潔高效的方式處理非同步程式碼。使用可選可逃逸閉包,我們可以將函式作為引數傳遞給其他函式並在稍後執行它們,即使在呼叫函式返回後也是如此。這使得編寫既易讀又易於維護的非同步程式碼變得容易。
可選可逃逸閉包可用於各種場景,例如網路請求、動畫和使用者介面更新。透過使用可選可逃逸閉包,我們可以編寫既高效又響應迅速的程式碼,而不會犧牲可讀性或可維護性。