完成处理程序导致不调用 Deinit

Posted

技术标签:

【中文标题】完成处理程序导致不调用 Deinit【英文标题】:Completion Handler Causes Deinit To Not Be Called 【发布时间】:2019-04-29 20:15:30 【问题描述】:

我有一个包含完成处理程序的网络任务,允许我确定任务是否以及何时成功完成;

func performUpload(url: URL, completionHandler: @escaping (_ response: Bool) -> ()) 
    photoSave.savePhotoRemote(assetURL: url)  response in
        completionHandler(response)
    

我从另一个 UIView 调用这个函数,使用以下方法;

UploadHelper.shared.performUpload(url: fileAssetPath)  response in
    if response 
       // do stuff
    

我注意到的是,当我捕获 responsedo stuff 时,调用此函数的类将永远不会 deinit。但是,如果我将功能更改为以下内容;

UploadHelper.shared.performUpload(url: fileAssetPath)  response in 

并且不对响应做任何事情,该类将取消初始化。

我的功能做错了什么?我想相应地捕获响应,但不以我的班级没有从内存中释放为代价。

【问题讨论】:

顺便说一句,虽然使用[weak self] 显然可以解决问题,但您完全有循环的事实很可能是由savePhotoRemote 将闭包保存在某些属性中引起的。本着防御性编程的精神,如果您曾经在属性中保存闭包,您可能还需要确保在调用闭包后nil 那个闭包属性(假设您不再需要它,就像这里的情况一样) .这并不能代替[weak self],而只是一个避免持续强引用循环的好习惯。 谢谢@Rob!这是非常有用的建议! 【参考方案1】:

你有一个保留周期。打破它。改变

UploadHelper.shared.performUpload(url: fileAssetPath)  response in
    if response 
       // do stuff
    

UploadHelper.shared.performUpload(url: fileAssetPath)  [unowned self] response in
    if response 
       // do stuff
    

【讨论】:

这是有道理的,并成功解决了我的问题。谢谢!

以上是关于完成处理程序导致不调用 Deinit的主要内容,如果未能解决你的问题,请参考以下文章

执行后台获取完成处理程序后应用程序崩溃

AVAudioPlayerNode scheduleFile:atTime:completionHandler: 不调用完成处理程序

Swift,带有完成处理程序的网络调用不起作用

完成处理程序调用太晚

测试 java 程序是不是调用 System.exist - 不退出 Junit

在闭包内调用完成处理程序的问题