带闭包的强引用循环
Strong reference cycles with closures
我正在尝试了解何时需要注意由强引用循环引起的可能的内存泄漏。根据我从 swift 文档中收集到的内容,在声明为实例 属性 的闭包中使用 self
引用在同一实例中将导致强引用循环,除非我声明一个捕获列表,例如:
class A {
var a: String
lazy var aClosure: () -> () = { [unowned self] in
println(self.a)
}
init(a: String) {
self.a = a
}
}
现在,对于未存储为实例属性的闭包或存储为其他 类 的实例属性的闭包,会发生什么情况?在这些情况下,我还需要担心强引用循环吗?
你问的情况不会导致引用循环。
仅当 2 个或多个对象直接或间接具有指向彼此的指针(或被 属性 内的块捕获)时才会发生引用循环:
A->B and B->A (direct)
A->B, B->C, C->A (indirect)
Now what happens with closures that aren't stored as instance properties
您经常会看到一个调用某些库并提供处理程序块的视图控制器。
例如:
// inside some method of view controller
APIWrapper.sharedInstance().callApiWithHandler(handler: {
(finished: Bool) -> Void in
// process result of the action
self.showResults()
}
在这种情况下,您不知道需要多长时间才能完成此操作。
您的区块可能会被提交到私有操作队列中。所有捕获的对象都将保持活动状态,直到此操作完成。
现在危险的部分甚至是:如果用户按下后退按钮(假设涉及导航控制器)并且当前视图控制器从导航堆栈中弹出,它将保持活动状态,因为捕获 self
即使它不会显示在屏幕上。
这应该重写为:
// inside some method of view controller
APIWrapper.sharedInstance().callApiWithHandler(handler: {
[weak self]
(finished: Bool) -> Void in
// process result of the action
self?.showResults()
}
closures that are stored as instance properties of other classes
这部分类似:您可能无法控制保持对块的引用的对象的生命周期。
捕获的对象是隐式引用,可能难以调试。
总而言之:使用块时,您应该始终考虑这个块将存在多长时间以及它是否产生循环。使用 weak
/unowned
捕获对象是一种很好的做法,除非您有充分的理由不这样做。
我正在尝试了解何时需要注意由强引用循环引起的可能的内存泄漏。根据我从 swift 文档中收集到的内容,在声明为实例 属性 的闭包中使用 self
引用在同一实例中将导致强引用循环,除非我声明一个捕获列表,例如:
class A {
var a: String
lazy var aClosure: () -> () = { [unowned self] in
println(self.a)
}
init(a: String) {
self.a = a
}
}
现在,对于未存储为实例属性的闭包或存储为其他 类 的实例属性的闭包,会发生什么情况?在这些情况下,我还需要担心强引用循环吗?
你问的情况不会导致引用循环。
仅当 2 个或多个对象直接或间接具有指向彼此的指针(或被 属性 内的块捕获)时才会发生引用循环:
A->B and B->A (direct)
A->B, B->C, C->A (indirect)
Now what happens with closures that aren't stored as instance properties
您经常会看到一个调用某些库并提供处理程序块的视图控制器。 例如:
// inside some method of view controller
APIWrapper.sharedInstance().callApiWithHandler(handler: {
(finished: Bool) -> Void in
// process result of the action
self.showResults()
}
在这种情况下,您不知道需要多长时间才能完成此操作。 您的区块可能会被提交到私有操作队列中。所有捕获的对象都将保持活动状态,直到此操作完成。
现在危险的部分甚至是:如果用户按下后退按钮(假设涉及导航控制器)并且当前视图控制器从导航堆栈中弹出,它将保持活动状态,因为捕获 self
即使它不会显示在屏幕上。
这应该重写为:
// inside some method of view controller
APIWrapper.sharedInstance().callApiWithHandler(handler: {
[weak self]
(finished: Bool) -> Void in
// process result of the action
self?.showResults()
}
closures that are stored as instance properties of other classes
这部分类似:您可能无法控制保持对块的引用的对象的生命周期。
捕获的对象是隐式引用,可能难以调试。
总而言之:使用块时,您应该始终考虑这个块将存在多长时间以及它是否产生循环。使用 weak
/unowned
捕获对象是一种很好的做法,除非您有充分的理由不这样做。