对于短期运行的操作,避免[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
完成。
在这种情况下,我们应该使用捕获列表来避免这种现象吗?我的推理正确吗,这里没有参考周期?
ViewController的生命周期可能会延长,直到dataTask完成为止
所以问题是那是否连贯。甚至可能是good事情。如果可以,那么就很好了,并且不需要weak self
,因为没有保留周期,因为网址会话已共享。
但是当url会话是一个实例时财产并拥有真正的代表,事情要复杂得多,您确实可以得到一个保留周期,因为该会话保留了可能保留该会话的委托。
如果您担心参考周期,那么在使用URL请求时通常不会得到一个参考周期。问题是URL请求迟早会结束(几分钟后),并且您的控制器将被释放。参考周期只是暂时的,不会导致内存泄漏。
问题是,即使用户已经关闭控制器并且也不会再显示它,您是否还要将控制器保留在内存中。它可能不会引起任何问题,但仍然很浪费。您正在保留不需要的内存,并且这些内存无法重复使用。
还请注意,在关闭控制器时,您实际上可能想取消正在运行的请求,以避免发送/接收不再需要的数据。
我认为,您不必过多担心参考周期,而应多考虑所有权。强有力的参考意味着某些东西是拥有的。该请求没有理由“拥有”控制器。这是另一种方式-控制器拥有并管理请求。如果没有所有权,为了清楚起见,我将使用weak
。
我的推理是否正确,这里没有参考周期?
这里没有参考周期。 ViewController
没有保留dataTask
完成处理程序。您可以认为这是因为iOS既对视图控制器和完成处理程序都保持了强大的引用,而完成处理程序也对视图控制器保持了很强的引用。没有从视图控制器返回到完成处理程序的强大引用,也没有对完成处理程序的引用的任何对象链的强大引用,因此您无需进行任何操作。在UIView.animate
中寻找相同的模式,在此您再次将闭包发送到iOS,而不是将它们存储在本地。
对于短期运行的操作,避免
[weak self]
是否可以接受?
<< duration并不是一个因素。两个相关的问题是:
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
实际上会导致内存泄漏。