iOS Swift 的捕获列表 [weak self] 和 [unowned self]
捕获列表(capture list)是 Swift 中闭包的重要概念之一,用来控制闭包如何捕获和存储其上下文中的外部变量。
捕获行为
在闭包中使用外部变量时,Swift 会自动捕获这些变量的引用。如果这些变量是引用类型(如类实例),闭包会持有它们的强引用,可能导致强引用循环,即内存泄漏。
捕获列表允许你明确指定闭包应该如何捕获这些外部变量,特别是在需要避免强引用循环时,你可以使用捕获列表来指定变量的捕获方式,如使用 weak
或 unowned
。
捕获列表的语法
捕获列表在闭包表达式的起始位置,放在方括号 []
中。每个捕获项都可以包含变量名、以及如何捕获该变量(weak
、unowned
等)。
语法格式:
{ [捕获列表] (参数) -> 返回类型 in // 闭包体 }
在 Swift 中,weak
和 unowned
都用于防止强引用循环,但它们有不同的特性和使用场景。核心区别在于,当引用的对象被释放时,它们的行为不同:
1. weak
引用
- 自动设为 nil:当被引用的对象被释放时,
weak
引用会自动变为nil
。 - 可选类型:由于
weak
引用可能会在对象被释放后变成nil
,因此它必须是可选类型(Optional
)。 - 使用场景:通常用于避免强引用循环,特别是在对象的生命周期可能比引用的闭包短时(即闭包执行时对象可能已被释放)。
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
的强引用,防止强引用循环。如果self
在闭包执行时被释放,self
会变为nil
,因此使用self?
来安全地访问其属性。
2. unowned
引用
- 不会设为 nil:
unowned
引用不会变为nil
,即使被引用的对象已经被释放。 - 非可选类型:
unowned
不需要声明为可选类型,因此它在使用时总是会假设对象存在。 - 使用场景:适用于闭包执行期间,对象一定会存在的情况。对象被释放后,再访问
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
表示闭包不持有对象的强引用,但假设对象在闭包执行期间仍然存在。如果在unowned
的场景中访问已经释放的对象,会发生运行时崩溃。
总结区别:
特性 | weak | unowned |
---|---|---|
是否会变为 nil |
是的,自动变为 nil |
否,不能变为 nil |
是否必须是可选类型 | 是,必须为可选类型(Optional ) |
否,不需要可选类型 |
是否会导致崩溃 | 不会,因为对象释放后会变成 nil |
会,如果对象已经释放,访问 unowned 会崩溃 |
使用场景 | 对象生命周期可能比闭包短 | 对象生命周期在闭包执行期间一定存在 |
何时使用:
- 使用
weak
:当你不确定对象的生命周期,可能会在闭包执行时已经被释放的情况下,使用weak
。(弱引用) - 使用
unowned
:当你确定对象在闭包的整个执行过程中都不会被释放时,可以使用unowned
。(无主引用)
posted on 2024-10-22 10:56 ACM_Someone like you 阅读(28) 评论(0) 编辑 收藏 举报