Swift 逃逸閉包和非逃逸閉包
在Swift中,閉包可以定義為自包含的代碼塊,可以在方法中傳遞或在我們的代碼中使用。愛掏網 - it200.com然而,我們可以定義兩種類型的閉包,即逃逸閉包和非逃逸閉包。愛掏網 - it200.com在Swift 5中,默認情況下,閉包參數是非逃逸的。愛掏網 - it200.com
閉包還可以在函數體內執行;如果我們需要逃逸閉包,我們可以將其標記為@escaping。愛掏網 - it200.com閉包可以捕獲和存儲來自其定義上下文的任何常量和變量的引用。愛掏網 - it200.com這被稱為閉包對這些常量和變量的封閉。愛掏網 - it200.com
在本文中,我們將討論逃逸閉包和非逃逸閉包。愛掏網 - it200.com我們還將討論為什么我們應該在我們的代碼中使用逃逸閉包。愛掏網 - it200.com
非逃逸閉包
當我們將閉包作為參數傳遞給函數時,函數執行閉包并返回給編譯器。愛掏網 - it200.com在這種情況下,一旦閉包被執行并執行結束,傳遞的閉包就會超出范圍,因此在內存中不再存在。愛掏網 - it200.com非逃逸閉包在其生命周期范圍內過渡到以下狀態。愛掏網 - it200.com
- 將閉包作為函數參數傳遞給函數調用。愛掏網 - it200.com
- 執行函數體。愛掏網 - it200.com
- 與函數體一起執行閉包。愛掏網 - it200.com
- 函數將編譯器返回。愛掏網 - it200.com
示例
讓我們考慮以下示例,其中函數接受一個非逃逸閉包作為參數。愛掏網 - it200.com
func calculate_Sum(_ array:Array, performSum:((Int) -> Void)){
var sum = 0
for i in array{
sum = sum + i
}
performSum(sum)
}
func calculation(){
var array = [0,1,2,3,4,5,6,7,8,9]
calculate_Sum(array) { (sum) in
debugPrint(sum)
}
}
在上面的示例中,我們將閉包傳遞給了一個函數,在同一個函數中將傳遞的數組的總和打印出來。愛掏網 - it200.com這里,函數calculate_Sum在函數體的末尾執行閉包。愛掏網 - it200.com
在這里,我們沒有跳過閉包的執行。愛掏網 - it200.com因此,一旦閉包執行完畢,它在內存中就不存在了。愛掏網 - it200.com
逃逸閉包
逃逸閉包與非逃逸閉包不同,因為我們可以保留逃逸閉包以便以后執行它們。愛掏網 - it200.com同時,函數體可以執行并返回給編譯器。愛掏網 - it200.com逃逸閉包的作用域存在,并且在執行之前將其存在在內存中。愛掏網 - it200.com我們可以根據需要使用逃逸閉包。愛掏網 - it200.com以下是逃逸閉包的幾種方式:
存儲
逃逸閉包的一種方式是將閉包保存在函數外定義的變量中,并在以后執行它。愛掏網 - it200.com這種方法用于需要使用啟動異步操作并接受閉包參數作為完成處理程序的函數的情況。愛掏網 - it200.com函數在啟動操作后返回,但是閉包參數被保存以便以后調用。愛掏網 - it200.com
考慮以下示例,其中calculate_Sum()接受一個逃逸閉包作為參數,保存在completionHandler中,它是一個類似閉包類型的變量。愛掏網 - it200.com在函數執行后,會調用completionHandler。愛掏網 - it200.com
var complitionHandler: ((Int)->Void)?
var sum = 0
func calculate_Sum(_ array:Array, performSum: @escaping ((Int) -> Void)){
for i in array{
sum = sum + i
}
complitionHandler = performSum
}
func calculation(){
sum = 0
var array = [0,1,2,3,4,5,6,7,8,9]
calculate_Sum(array) { (sum) in
debugPrint(sum)
}
}
calculation()
complitionHandler!(sum)
異步執行
當我們在DispatchQueue上異步執行閉包時,閉包會被隊列保存在內存中以便將來使用。愛掏網 - it200.com在這種情況下,我們無法確定閉包何時會被執行。愛掏網 - it200.com考慮以下示例。愛掏網 - it200.com
func calculate_Sum(_ array:Array, performSum: @escaping ((Int) -> Void)){
var sum = 0
for i in array{
sum = sum + i
}
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
performSum(sum)
}
}
func calculation(){
let array = [0,1,2,3,4,5,6,7,8,9]
calculate_Sum(array) { (sum) in
debugPrint(sum)
}
}
calculation()