3

我正在尝试关闭保留周期,如下所示

 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在做之前是 nil outself?.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

我的问题是为什么strongSelfsample = nil. 是不是因为之前在闭包里面被捕获了sample = nil

4

1 回答 1

3

让我们考虑您的第二个示例:

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)
}

这是一种常见的模式,它有效地表示“如果self已被释放,return则立即,否则建立强引用strongSelf,并保持此强引用直到关闭完成。”

所以,在你的例子中,self不是nil这个分派块开始的时候,所以一旦我们指定strongSelf引用它,我们现在有两个对该对象的强引用,在这个闭包Sample中的原始sample引用和这个新引用。strongSelf

因此,当您的其他线程删除它自己sample对该Sample对象的强引用时(通过超出范围或通过显式设置samplenil),该strongSelf强引用仍然存在并且将防止对象被释放(或至少直到这个分派的块完成)。

在您上面的评论中,您问:

我仍然不明白为什么strongSelf自从 selfnil出来后没有改变......

强引用永远不会nil仅仅因为其他一些强引用(即使它是原始强引用)被设置为nil. 设置为引用的行为nil仅适用于weak引用,而不适用于强引用。

当您的代码sample = nil在第一个线程上执行时,所做的只是删除强引用。它不会删除对象或类似的东西。它只是删除了它的强引用。现在调度块有它自己的强引用,所有发生的事情sample = nil是有两个强引用的对象现在只剩下一个强引用(strongSelf调度块中的引用)。只有当这个最终的强引用被移除时,对象才会被释放并被deinit调用。

于 2016-08-05T04:41:49.083 回答