1

ARC上有很多教程。但是我不明白 unowned 或 weak 的明确工作是如何引用捕获的变量变为空的。

苹果文档:

当闭包和它捕获的实例总是相互引用时,将闭包中的捕获定义为无主引用,并且总是同时被释放。

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

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

闭包在其主体内引用 self(作为引用 self.string 的一种方式),闭包捕获 self,这意味着它持有对 RetainCycle 实例的强引用。两者之间形成了一个强参考循环。通过无主它的中断引用循环。

但我想了解哪种情况不会同时相互解除分配,而 Unowned self 变为 null 只是想让它崩溃。?

4

2 回答 2

1

正如我所知道的,您问如何在关闭运行时 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持有我的, 会发生什么。UIImageView它因为imageView被释放而崩溃,但关闭仍然存在并试图到达它的image属性。据我所知,你想学习这个。

我更改了unowned参考来weak解决这个问题。

于 2019-03-05T15:47:14.490 回答
0

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

这不是真的。它有一个对 RetainCycle 实例的无主引用。这与强参考不同。

但我想了解哪种情况不会同时相互解除分配,而 Unowned self 变为 nil 我只想让它崩溃。?

任何时间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]也不总是答案。

于 2019-03-05T18:39:52.453 回答