iOS Swift 的捕獲列表 [weak self] 和 [unowned self]
捕獲列表(capture list)是 Swift 中閉包的重要概念之一,用來控制閉包如何捕獲和存儲其上下文中的外部變量。
捕獲行為
在閉包中使用外部變量時,Swift 會自動捕獲這些變量的引用。如果這些變量是引用類型(如類實例),閉包會持有它們的強引用,可能導致強引用循環(huán),即內存泄漏。
捕獲列表允許你明確指定閉包應該如何捕獲這些外部變量,特別是在需要避免強引用循環(huán)時,你可以使用捕獲列表來指定變量的捕獲方式,如使用 weak 或 unowned。
捕獲列表的語法
捕獲列表在閉包表達式的起始位置,放在方括號 [] 中。每個捕獲項都可以包含變量名、以及如何捕獲該變量(weak、unowned 等)。
語法格式:
{ [捕獲列表] (參數(shù)) -> 返回類型 in
// 閉包體
}
在 Swift 中,weak 和 unowned 都用于防止強引用循環(huán),但它們有不同的特性和使用場景。核心區(qū)別在于,當引用的對象被釋放時,它們的行為不同:
1. weak 引用
- 自動設為 nil:當被引用的對象被釋放時,
weak引用會自動變?yōu)?nbsp;nil。 - 可選類型:由于
weak引用可能會在對象被釋放后變成nil,因此它必須是可選類型(Optional)。 - 使用場景:通常用于避免強引用循環(huán),特別是在對象的生命周期可能比引用的閉包短時(即閉包執(zhí)行時對象可能已被釋放)。
class MyClass { var value = 10 func printValue() { let closure = { [weak self] in print(self?.value ?? 0) } closure() // 輸出 10 } } let myClass = MyClass() myClass.printValue()
//在這個例子中,捕獲列表[weak self]指定self以弱引用的方式捕獲,避免了閉包對self的強引用,防止強引用循環(huán)。如果self在閉包執(zhí)行時被釋放,self會變?yōu)?nbsp;nil,因此使用self?來安全地訪問其屬性。
2. unowned 引用
- 不會設為 nil:
unowned引用不會變?yōu)?nbsp;nil,即使被引用的對象已經被釋放。 - 非可選類型:
unowned不需要聲明為可選類型,因此它在使用時總是會假設對象存在。 - 使用場景:適用于閉包執(zhí)行期間,對象一定會存在的情況。對象被釋放后,再訪問
unowned引用會導致程序崩潰(runtime error)。
class MyClass { var value = 10 func printValue() { let closure = { [unowned self] in print(self.value) } closure() // 輸出 10 } } let myClass = MyClass() myClass.printValue()
//unowned表示閉包不持有對象的強引用,但假設對象在閉包執(zhí)行期間仍然存在。如果在unowned的場景中訪問已經釋放的對象,會發(fā)生運行時崩潰。
總結區(qū)別:
| 特性 | weak | unowned |
|---|---|---|
是否會變?yōu)?nbsp;nil |
是的,自動變?yōu)?nbsp;nil |
否,不能變?yōu)?nbsp;nil |
| 是否必須是可選類型 | 是,必須為可選類型(Optional) |
否,不需要可選類型 |
| 是否會導致崩潰 | 不會,因為對象釋放后會變成 nil |
會,如果對象已經釋放,訪問 unowned 會崩潰 |
| 使用場景 | 對象生命周期可能比閉包短 | 對象生命周期在閉包執(zhí)行期間一定存在 |
何時使用:
- 使用
weak:當你不確定對象的生命周期,可能會在閉包執(zhí)行時已經被釋放的情況下,使用weak。(弱引用) - 使用
unowned:當你確定對象在閉包的整個執(zhí)行過程中都不會被釋放時,可以使用unowned。(無主引用)
posted on 2024-10-22 10:56 ACM_Someone like you 閱讀(172) 評論(0) 收藏 舉報
浙公網安備 33010602011771號