ios - 如何摆脱等待完成处理程序
问题描述
我在用户单击按钮时加载内容,等待下载并向用户显示内容。我使用URLSession.shared.dataTask
并返回响应为(completion: @escaping closure (_ data: Data?) -> Void)
但是,如果用户想在内容加载之前离开控制器,那么self.navigationController?.popViewController (animated: true)
这个控制器会保留在内存中(deinit{}
不要调用)。据我了解,这是因为控制器期待完成处理程序回调。
我应该使用什么以及如何使用,以便当用户关闭此视图控制器时,他将从内存中删除,而不是永远留在那里(直到用户终止应用程序)?
解决方案
你说:
据我了解,这是因为控制器期待完成处理程序回调。
如果视图控制器没有被释放,那是因为对它有一个挥之不去的强引用。在您的情况下,听起来您的关闭保持了强大的参考。为避免保留该强引用,您将[weak self]
在闭包中使用捕获列表,例如
let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in // note `[weak self]` capture list
guard let self = self else { return } // safely unwrap the optional
... // the rest of this like before
}
task.resume()
如果您想更进一步,您还可以在离开时取消任务,例如
private weak var savedTask: URLSessionTask?
deinit {
savedTask?.cancel() // cancel if if it hasn't finished already
}
func foo() {
...
let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in // note `[weak self]` capture list
guard let self = self else { return } // safely unwrap the optional
... // the rest of this like before
}
task.resume()
savedTask = task
}
这样,如果网络请求的唯一目的是更新 UI,我们可以在不再需要请求的数据时释放网络资源。
所有这一切都假设这是您拥有的唯一挥之不去的强引用(即,您看到deinit
在网络请求完成时被调用)。如果没有,请确保所有异步闭包都使用弱引用,并且您没有任何强引用循环。常见的问题来源是重复计时器、观察者等,或传统的强参考循环。(您可以使用“调试内存图”功能来确定这些强引用的位置,例如此答案中所述。)
推荐阅读
- python - tf.compat.v1.train.exponential_decay:全局步长 = 0
- symfony - Symfony messenger 工作人员在主管下运行时不会停止
- azure-devops - 使用负载均衡器部署到多台服务器
- airflow - Airflow - 只有在另一个 DAG 上的所有任务都成功时才运行 DAG
- python-3.x - 复制没有父文件夹的子文件夹
- javascript - 如何遍历地图并仅获取前几个键值对并将它们传递给另一个函数?
- java - 每当我将文件保存为文件类型 java 时,VS 代码都会打开 .class 文件而不是“.java”文件,并且不会创建 .java 文件
- javascript - 表单提交的时间戳
- python - 如何手动实现 pytorch 卷积的填充
- excel - 根据下拉选择自动填充单元格