Ios 避免简单操作的[弱自我]?

Ios 避免简单操作的[弱自我]?,ios,swift,memory-management,urlsession,Ios,Swift,Memory Management,Urlsession,对于短时间运行的操作,是否可以避免[弱自我]?例如,URLSession将保留来自dataTask的闭包(带有:completion:): 在这种情况下,闭包会强烈地捕获self,这意味着即使闭包将此ViewController保存在内存中URLSession将保持关闭直到数据任务完成,这意味着ViewController的生命周期可能会延长到dataTask完成 在这种情况下,我们应该使用捕获列表来避免这种行为吗?我的推理正确吗,这里没有引用循环 ViewController的生命周期可能会延

对于短时间运行的操作,是否可以避免
[弱自我]
?例如,
URLSession
将保留来自
dataTask的闭包(带有:completion:)

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

在这种情况下,我们应该使用捕获列表来避免这种行为吗?我的推理正确吗,这里没有引用循环

ViewController的生命周期可能会延长到dataTask完成

因此,问题是这是否是连贯的。这甚至可能是件好事。如果可以的话,那就好了,而且不需要
弱自我
,因为没有保留周期,因为 url会话是共享的

但是当url会话是一个实例时 属性并有一个真正的委托,事情就复杂多了
您确实可以获得一个保留周期,因为会话保留其委托,而委托可能会保留会话

如果您担心引用周期,那么在使用URL请求时通常不会得到引用周期。问题是URL请求迟早会完成(几分钟后),并且您的控制器会被释放。引用循环只是临时的,不会导致内存泄漏

问题是,即使用户已经关闭了控制器,并且不再显示,您是否希望将控制器保留在内存中。这可能不会引起任何问题,但仍然是浪费。你持有的是你不需要的、不能重复使用的内存

还请注意,当控制器被解除时,您实际上可能希望取消正在运行的请求,以避免发送/接收不再需要的数据

在我看来,您不应该太担心引用周期,而应该更多地考虑所有权。强引用意味着拥有某个东西。请求没有理由“拥有”控制器。相反,控制器拥有并管理请求。如果没有所有权,我会使用
,只是为了清楚起见

我的推理正确吗,这里没有引用循环

这里没有参考循环<代码>视图控制器未保留
数据任务
完成处理程序。您可以将此视为iOS保留对视图控制器和完成处理程序的强引用,并且完成处理程序也保留对视图控制器的强引用。没有从视图控制器返回到完成处理程序的强引用,也没有到任何引用完成处理程序的对象链的强引用,因此您是无周期的。在
UIView.animate
中查找相同的模式,在这里您再次向iOS发送闭包,而不是将它们存储在本地

对于短时间运行的操作,是否可以避免
[弱自我]

工作的持续时间不是一个因素。这两个相关问题是:

  • 是否存在引用循环
  • 引用的循环会被打破吗
  • 举个例子:

    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
    在实践中会导致内存泄漏。

    我想您已经得到了答案。这不是一个参考周期

    但要建立一个系统的方法,我的建议是一个更简单的方法。忘了考虑泄密之类的事情吧

    考虑所有权流量控制,然后考虑内存管理

    • 所有权:此对象是否需要拥有此其他对象?对象是否应该拥有其委托?子视图应该拥有其父视图吗?此请求是否拥有此viewController
    • 流控制:我要多久取消分配此对象?是立即还是在视图从屏幕上移除时
    • 内存管理:这是一个强引用周期吗

    这个思考过程不仅帮助您区分真正的内存泄漏和非泄漏。它还可以帮助您更好地设计和阅读代码,而不仅仅是盲目地到处乱扔
    [脆弱的自我]

    您肯定应该在这里使用
    [weak self]
    ,这不是因为存在强引用循环的任何风险,而是因为此闭包的存在只是为了更新标签。编写故意将视图控制器及其视图保留在内存中以便更新vi中的标签的代码是没有意义的
    class StillBadVC: UIViewController {
        private lazy var cycleMaker: () -> Void = { print(self) }
    
        override func loadView() {
            view = UIView()
            cycleMaker()
        }
    
        func breakCycle() {
            cycleMaker = { }
        }
    }