【问题标题】:How Unowned reference works with capture variables in SwiftUnowned 引用如何与 Swift 中的捕获变量一起使用
【发布时间】:2019-03-05 11:36:09
【问题描述】:

有很多关于 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 其中断引用循环。

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

【问题讨论】:

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


【解决方案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 被取消,我的关闭仍然存在。

那么,如果我在下载完成之前关闭了持有我的UIImageViewviewController,会发生什么情况。它崩溃是因为 imageView 被释放,但关闭仍然存在并试图到达它的 image 属性。据我所知,你想学习这个。

我将unowned 的引用更改为weak 来解决这个问题。

【讨论】:

    【解决方案2】:

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

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

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

    任何时候closureRetainCycle 之外的东西捕获,因此比它的所有者更长寿:

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

    【讨论】:

      猜你喜欢
      • 2015-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多