将引用转换回闭包内的强引用,内存管理,swift
convert the reference back to a strong one inside the closure, memory management, swift
我正在像下面这样在闭包中试验保留周期
class Sample {
deinit {
print("Destroying Sample")
}
func additionOf(a: Int, b:Int) {
print("Addition is \(a + b)")
}
func closure() {
dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in
self?.additionOf(3, b: 3)
usleep(500)
self?.additionOf(3, b: 5)
}
}
}
稍后,我正在做
var sample : Sample? = Sample()
sample?.closure()
dispatch_async(dispatch_get_global_queue(0, 0)) {
usleep(100)
sample = nil
}
输出将是
Addition is 6
Destroying Sample
这是可以理解的,因为 self
在执行 self?.additionOf(3, b:5)
之前是 nil
如果我通过创建另一个引用 [weak self]
的变量在闭包内部进行更改,如下所示
dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in
guard let strongSelf = self else { return }
strongSelf.additionOf(3, b: 3)
usleep(500)
strongSelf.additionOf(3, b: 5)
}
这次的输出是
Addition is 6
Addition is 8
Destroying C
我的问题是为什么 strongSelf
在 sample = nil
之后不为零。是不是因为在sample = nil
之前在闭包里面被捕获了
让我们考虑你的第二个例子:
dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in
guard let strongSelf = self else { return }
strongSelf.additionOf(3, b: 3)
usleep(500)
strongSelf.additionOf(3, b: 5)
}
这是一个常见的模式,它实际上表示 "if self
has been deallocated, return
immediately, otherwise establish a strong reference, strongSelf
, and maintain this strong reference until the closure finishes."
所以,在你的例子中,当这个调度块开始时,self
不是 nil
,所以一旦我们分配 strongSelf
来引用它,我们现在有两个强对此 Sample
对象的引用,包括原始 sample
引用和此闭包内的新 strongSelf
引用。
因此,当您的其他线程删除了自己对该 Sample
对象的强引用 sample
时(通过超出范围或将 sample
显式设置为 nil
),这个 strongSelf
强引用仍然存在,并且会阻止对象被释放(或者至少直到这个分派块完成)。
在你上面的评论中,你问:
I still not understand why strongSelf
does not get changed since self is nil
out...
强引用永远不会设置为 nil
只是因为其他一些强引用(即使它是原始强引用)被设置为 nil
。将引用设置为 nil
的行为仅适用于 weak
引用,不适用于强引用。
当您的代码在第一个线程上执行 sample = nil
时,所做的只是删除强引用。它不会删除对象或类似的东西。它只是删除了它的强引用。现在分派的块有它自己的强引用,所有发生在 sample = nil
上的是有两个强引用的对象现在只剩下一个强引用(分派块中的 strongSelf
引用) .只有当这个最终的强引用被移除时,对象才会被释放并调用deinit
。
我正在像下面这样在闭包中试验保留周期
class Sample {
deinit {
print("Destroying Sample")
}
func additionOf(a: Int, b:Int) {
print("Addition is \(a + b)")
}
func closure() {
dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in
self?.additionOf(3, b: 3)
usleep(500)
self?.additionOf(3, b: 5)
}
}
}
稍后,我正在做
var sample : Sample? = Sample()
sample?.closure()
dispatch_async(dispatch_get_global_queue(0, 0)) {
usleep(100)
sample = nil
}
输出将是
Addition is 6
Destroying Sample
这是可以理解的,因为 self
在执行 self?.additionOf(3, b:5)
如果我通过创建另一个引用 [weak self]
的变量在闭包内部进行更改,如下所示
dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in
guard let strongSelf = self else { return }
strongSelf.additionOf(3, b: 3)
usleep(500)
strongSelf.additionOf(3, b: 5)
}
这次的输出是
Addition is 6
Addition is 8
Destroying C
我的问题是为什么 strongSelf
在 sample = nil
之后不为零。是不是因为在sample = nil
让我们考虑你的第二个例子:
dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in
guard let strongSelf = self else { return }
strongSelf.additionOf(3, b: 3)
usleep(500)
strongSelf.additionOf(3, b: 5)
}
这是一个常见的模式,它实际上表示 "if self
has been deallocated, return
immediately, otherwise establish a strong reference, strongSelf
, and maintain this strong reference until the closure finishes."
所以,在你的例子中,当这个调度块开始时,self
不是 nil
,所以一旦我们分配 strongSelf
来引用它,我们现在有两个强对此 Sample
对象的引用,包括原始 sample
引用和此闭包内的新 strongSelf
引用。
因此,当您的其他线程删除了自己对该 Sample
对象的强引用 sample
时(通过超出范围或将 sample
显式设置为 nil
),这个 strongSelf
强引用仍然存在,并且会阻止对象被释放(或者至少直到这个分派块完成)。
在你上面的评论中,你问:
I still not understand why
strongSelf
does not get changed since self isnil
out...
强引用永远不会设置为 nil
只是因为其他一些强引用(即使它是原始强引用)被设置为 nil
。将引用设置为 nil
的行为仅适用于 weak
引用,不适用于强引用。
当您的代码在第一个线程上执行 sample = nil
时,所做的只是删除强引用。它不会删除对象或类似的东西。它只是删除了它的强引用。现在分派的块有它自己的强引用,所有发生在 sample = nil
上的是有两个强引用的对象现在只剩下一个强引用(分派块中的 strongSelf
引用) .只有当这个最终的强引用被移除时,对象才会被释放并调用deinit
。