无主引用如何与Swift中的捕获变量一起使用

时间:2019-03-05 11:36:09

标签: swift automatic-ref-counting unowned-references

关于ARC的教程很多。但是由于引用捕获的变量如何变为空值,我无法理解无主或弱项的清晰工作。

Apple Document:

  

将闭包中的捕获定义为闭包时的无主引用   它捕获的实例将始终相互引用,并且将   总是在同一时间释放。

class RetainCycle {
        var closure: (() -> Void)!
        var string = "Hello"

        init() {
            closure = { [unowned self] in
                self.string = "Hello, World!"
            }
        }
    }

闭包在其主体内引用self(作为引用self.string的一种方式),闭包捕获self,这意味着它持有对RetainCycle实例的强引用。两者之间会建立一个强大的参考周期。凭空打破了其参考周期。

但是我想了解哪种情况不会同时相互解除,而Unown self变为null只是想使其崩溃。

2 个答案:

答案 0 :(得分:1)

据我所知,您问closue运行时self如何为空。如果我做对了,我可以举一个我以前见过的非常相似的例子。

我为UIImageView编写了一个扩展,可以从给定的链接下载图像并像这样进行设置。

public extension UIImageView{
  func downloadImage(link: String){
    let url = URL(string:link)
    URLSession.shared.dataTask(with: url){ [unowned self]
      if let image = UIImage(data: data){
        DispatchQueue.main.async{
          self.image = image
        }
      }
    }
    task.start()
  }
}

但是有一个问题。下载图像是一项后台任务。我将完成方法设置为UrlSession并增加了其引用计数。因此,即使取消了imageView的关闭,我的关闭仍然存在。

因此,如果在下载完成之前关闭保存我的viewController的{​​{1}}会发生什么情况。由于UIImageView被释放而崩溃,但闭包仍然存在,并尝试到达其imageView属性。就我所知,您想学习这一点。

我将image的引用更改为unowned,以解决此问题。

答案 1 :(得分:0)

  

这意味着它拥有对RetainCycle实例的强大引用

这不是事实。它具有对RetainCycle实例的无归属引用。这与强大的参考资料不一样。

  

但是我想了解哪种情况不会同时将它们相互释放,而无主自我变成零我只想崩溃。

任何时候closure都被RetainCycle之外的东西捕获,从而超过了它的所有者:

var rc: RetainCycle? = RetainCycle()   // create an RC

let cl = rc?.closure  // Hold onto its closure

rc = nil // Deallocate the RC

cl?() // Access the closure safely, but its reference to `self` is invalid. Crash.

通常,涉及unowned self的闭包应该不能在self之外引用。有时很难知道这是真的。例如,以下是最近使我使用的应用崩溃的情况:

var completion: (() -> Void)?

...

DispatchQueue.main.async { [unowned self] in
    self.completion()
    self.completion = nil
}

感觉很好,但是如果self在进入主队列块的时间与运行该块的时间之间被释放,则繁荣。

顺便说一句,在这种情况下,正确的答案应该是常规的强self。我们想要保留循环,以使该对象一直存在直到其完成处理程序运行为止,此时该块消失,对self的引用消失,并且self正确释放。因此,[weak self]也不总是答案。