避免[弱自我]进行简单操作?

问题描述 投票:3回答:4

对于短期运行的操作,避免[weak self]是否可以接受?例如,URLSession将保留dataTask(with:completion:)中的闭包:

final class ViewController: UIViewController {
  let label = UILabel()

  override func viewDidLoad() {
    super.viewDidLoad()
    URLSession.shared.dataTask(with: url) { data, response, error in
      let decodedString = String(bytes: data, encoding: .utf8)

      DispatchQueue.main.async {
        self.label.text = decodedString
      }
    }
  }
}

在这种情况下,闭包强烈捕获self,这意味着即使ViewController被闭包保存在内存中。 URLSession将保持关闭状态,直到完成数据任务为止,这意味着ViewController的生命周期可以延长,直到dataTask完成。

在这种情况下,我们应该使用捕获列表来避免这种现象吗?我的推理正确吗,这里没有参考周期?

ios swift memory-management urlsession
4个回答
3
投票

ViewController的生命周期可能会延长,直到dataTask完成为止

所以问题是那是否连贯。甚至可能是good事情。如果可以,那么就很好了,并且不需要weak self,因为没有保留周期,因为网址会话已共享。

但是当url会话是一个实例时财产并拥有真正的代表,事情要复杂得多,您确实可以得到一个保留周期,因为该会话保留了可能保留该会话的委托。


3
投票

如果您担心参考周期,那么在使用URL请求时通常不会得到一个参考周期。问题是URL请求迟早会结束(几分钟后),并且您的控制器将被释放。参考周期只是暂时的,不会导致内存泄漏。

问题是,即使用户已经关闭控制器并且也不会再显示它,您是否还要将控制器保留在内存中。它可能不会引起任何问题,但仍然很浪费。您正在保留不需要的内存,并且这些内存无法重复使用。

还请注意,在关闭控制器时,您实际上可能想取消正在运行的请求,以避免发送/接收不再需要的数据。

我认为,您不必过多担心参考周期,而应多考虑所有权。强有力的参考意味着某些东西是拥有的。该请求没有理由“拥有”控制器。这是另一种方式-控制器拥有并管理请求。如果没有所有权,为了清楚起见,我将使用weak


1
投票

我的推理是否正确,这里没有参考周期?

这里没有参考周期。 ViewController没有保留dataTask完成处理程序。您可以认为这是因为iOS既对视图控制器和完成处理程序都保持了强大的引用,而完成处理程序也对视图控制器保持了很强的引用。没有从视图控制器返回到完成处理程序的强大引用,也没有对完成处理程序的引用的任何对象链的强大引用,因此您无需进行任何操作。在UIView.animate中寻找相同的模式,在此您再次将闭包发送到iOS,而不是将它们存储在本地。

对于短期运行的操作,避免[weak self]是否可以接受?

<< duration并不是一个因素。两个相关的问题是:

    是否存在参考周期?
  1. 引用循环会被打破吗?
  • 举这个例子:

    class BadVC: UIViewController { private lazy var cycleMaker: () -> Void = { print(self) } override func loadView() { view = UIView() cycleMaker() } }

    BadVC在这里设法创建一个参考循环,该参考循环在加载其视图后将永不中断。 cycleMaker()将在纳秒内执行的事实并不能使我们免于内存泄漏。


    实用上有第三个问题:

      此代码是否以一种难以理解,容易破坏或不可靠的方式避免了永久的参考周期,所以将来由于滥用或修改而可能会出现参考周期?
  • 您可以手动中断参考循环。例如:

    class StillBadVC: UIViewController { private lazy var cycleMaker: () -> Void = { print(self) } override func loadView() { view = UIView() cycleMaker() } func breakCycle() { cycleMaker = { } } }

    [这里,我们处于危险之中,因为StillBadVC强烈引用了cycleMaker,而cycleMaker引用了强烈引用了StillBadVC。只要有人记得调用breakCycle(),该循环就会中断,这时视图控制器将删除其对cycleMaker的强引用,从而允许cycleMaker取消分配。但是,如果有人忘记致电breakCycle(),该循环将被打破。调用名为breakCycle()的方法通常不是使用视图控制器的约定的一部分,因此我们希望StillBadVC实际上会导致内存泄漏。

  • 0
    投票
    © www.soinside.com 2019 - 2024. All rights reserved.