当前位置: 首页 > 知识库问答 >
问题:

在Swift中,我们是否总是使用[无主自我]内部关闭

吕永寿
2023-03-14

在 WWDC 2014 年第 403 届会议中级 Swift 和脚本中,有以下幻灯片

演讲者说,在那种情况下,如果我们不在那里使用< code>[unowned self],就会出现内存泄漏。这是否意味着我们应该总是在闭包内使用< code>[unowned self]?

在Swift Weather应用程序ViewController.swift的第64行,我不使用[无主自我]。但是我通过使用一些@IBOutlet来更新UI,例如self.temperatureself.loadingIndicator。这可能是可以的,因为我定义的所有@IBOutlet都是。但是为了安全起见,我们应该始终使用[无主自我]吗?

class TempNotifier {
  var onChange: (Int) -> Void = {_ in }
  var currentTemp = 72
  init() {
    onChange = { [unowned self] temp in
      self.currentTemp = temp
    }
  }
}

共有3个答案

汪典
2023-03-14

我想我会为视图控制器添加一些具体的示例。许多解释,不仅仅是这里关于堆栈溢出的解释,都非常好,但我对真实世界的例子做得更好(@drewag在这方面有一个良好的开端):

>

  • 如果您有一个闭包来处理网络请求的响应,请使用,因为它们的寿命很长。视图控制器可以在请求完成之前关闭,因此在调用关闭时,self不再指向有效对象
  • 如果您有处理按钮上事件的闭包。这可以是无主,因为视图控制器一离开,按钮和它可能从self引用的任何其他项目就会同时离开。封闭块也将同时消失。

    class MyViewController: UIViewController {
          @IBOutlet weak var myButton: UIButton!
          let networkManager = NetworkManager()
          let buttonPressClosure: () -> Void // closure must be held in this class. 
    
          override func viewDidLoad() {
              // use unowned here
              buttonPressClosure = { [unowned self] in
                  self.changeDisplayViewMode() // won't happen after vc closes. 
              }
              // use weak here
              networkManager.fetch(query: query) { [weak self] (results, error) in
                  self?.updateUI() // could be called any time after vc closes
              }
          }
          @IBAction func buttonPress(self: Any) {
             buttonPressClosure()
          }
    
          // rest of class below.
     }
    

  • 牧业
    2023-03-14

    我写了一篇关于这个问题的文章,扩展了这个答案(查看SIL以了解ARC的功能),请在这里查看。

    前面的答案并没有给出什么时候使用一个而不是另一个的简单规则,为什么,所以让我补充一些东西。

    无主或弱讨论归结为变量的生存期和引用它的闭包问题。

    您可以有两种可能的情况:

    >

  • 闭包具有与变量相同的生存期,因此只有在变量可访问之前才能访问闭包。变量和闭包具有相同的生存期。在这种情况下,应将引用声明为无主引用。一个常见的例子是[无主的自我]在许多例子中使用的小闭包,这些闭包在父母的上下文中做了一些事情,并且没有在其他地方被引用不会比他们的父母活得更久。

    闭包生命周期独立于变量之一,当变量不再可达时,闭包仍然可以被引用。在这种情况下,您应该将引用声明为弱引用并在使用它之前验证它不是nil(不要强制展开)。一个常见的例子是[弱委托],您可以在一些引用完全不相关(按生命周期计算)委托对象的闭包示例中看到。

    那么,实际上大部分时间你会/应该使用哪个?

    引用twitter上乔·格罗夫的话:

    无主更快,并允许不变性和非选择性。

    如果你不需要弱,就不要使用它。

    您将在这里找到关于unowned*内部工作的更多信息。

    < code>*通常也称为unowned(safe ),表示在访问无主引用之前执行运行时检查(导致无效引用崩溃)。

  • 弘承业
    2023-03-14

    不,肯定有时候你不想使用[无主的自己]。有时,您希望闭包捕获自我,以确保在调用闭包时它仍然存在。

    如果您正在发出异步网络请求,您确实希望闭包在请求完成时保留self。该对象可能已被释放,但您仍然希望能够处理请求完成。

    你唯一真正想要使用[无主的自我][弱的自我]的时候,就是你创建一个强大的参考周期的时候。一个强大的参考循环是当存在一个所有权循环时,对象最终相互拥有(可能通过第三方),因此它们永远不会被解除分配,因为它们都确保彼此保持。

    在闭包的特定情况下,您只需要意识到在闭包内部引用的任何变量都被闭包“拥有”。只要闭包在附近,那些对象就保证在附近。停止这种所有权的唯一方法,就是做< code >[无主自我]或< code >[虚弱自我]。因此,如果一个类拥有一个闭包,并且这个闭包捕获了对该类的强引用,那么在闭包和类之间就有一个强引用循环。这也包括类是否拥有拥有闭包的东西。

    在幻灯片上的示例中,TempNotifier 通过 onChange 成员变量拥有闭包。如果他们不宣布自我无主,那么闭包也将拥有自我,从而形成一个强大的参考循环。

    无主者之间的区别在于,被声明为可选,而无主则不是。通过声明它,你可以处理它在某些时候在闭包内可能为零的情况。如果您尝试访问碰巧为 nil 的无主变量,它将使整个程序崩溃。因此,只有在您为正值时才使用无主变量,而闭包在周围时,该变量将始终存在

     类似资料:
    • 问题内容: 伙计们,我们是像其他任何类一样从Object继承的(当然,我们不必明确声明除外)还是对Object类有一些特殊的特权,并且它不像其他类那样继承? 问题答案: 不,是一样的。这是JLS 8.1.3 的摘录: 如果任何其他类的类声明都没有extends子句,则该类会将其作为其隐式直接超类。 当然,它本身有点特殊(JLS): 每个类都只是单个现有类(第8.1.3节)的扩展(即其子类),并且可

    • 问题内容: Java中是否经常使用内部类?这些与嵌套类相同吗?还是用Java更好的替代了它们?我有一本关于版本5的书,其中有一个使用内部类的示例,但是我想我读过一些内部类是“不好的”。 我不知道,希望对此有所想法。 谢谢。 问题答案: 内部类经常使用,非常相似的类(匿名类)实际上是必不可少的,因为它们是Java与闭包最接近的东西。因此,如果您不记得自己听到内部类不好的地方,请尝试忘记它!

    • 问题内容: 昨天,当我回答使用迭代器并删除时出现ConcurrentModificationException错误的问题时,我添加了一条通知 当您有ArrayLists时,使用迭代器不是一个好主意。 您无需深刻理解该问题即可回答该问题。 在那里,我有两条评论是我错了。 我的论点: 迭代器不易读取代码。 有可能引发难以调试的ConcurrentModificationException。 你能解释一

    • 问题内容: 我只是想知道是否需要TimeSpan,以便我可以定义两次之间的时,分,秒。 由此我们可以有两次之间的时间间隔。喜欢 要么 有了这个,我们就可以用它了。 我不确定这是否已经在Java中实现但尚未被我发现。 问题答案: 借助SDK中的JDK 8日期时间库,您可以使用 要么 来自JodaTime的会.. 时间间隔表示两个时刻之间的时间段。间隔包括开始时刻,不包括结束。结束时刻始终大于或等于开

    • 我试图知道我的频道是否在YouTube上流式传输。我正在将youtube api v3与php库一起使用。我能够通过liveBroadcasts.list获得最后的广播,但是当我开始使用OBS进行流式传输时,我将参数 broadcastStatus = active 放在一起,并且不返回任何内容。我也尝试过liveStreams.list,但我仍然一无所获。我不知道我做错了什么,有人可以解释一下吗

    • 问题内容: 我对使用数据库非常陌生。现在我可以写,,,和命令。但是我看过很多我们喜欢写的论坛: …代替: 为什么我们总是喜欢使用参数,我将如何使用它们? 我想知道第一种方法的用途和好处。我什至听说过SQL注入,但是我不太了解。我什至不知道SQL注入是否与我的问题有关。 问题答案: 当数据库与程序界面(例如桌面程序或网站)结合使用时,使用参数有助于防止 SQL注入攻击 。 在您的示例中,用户可以通过