ios - 如何摆脱等待完成处理程序

标签 ios swift closures nsurlsession

当用户单击按钮时,我加载内容,等待下载并向用户显示内容。 我使用 URLSession.shared.dataTask 并将响应返回为 (completion: @escaping Closure (_ data: Data?) -> Void)

但是,如果用户想在加载内容之前离开 Controller ,则使用 self.navigationController?.popViewController (animated: true) 该 Controller 保留在内存中(deinit{} 不调用)。据我了解,这是因为 Controller 正在等待完成处理程序回调。

我应该使用什么以及如何使用,以便当用户关闭此 View Controller 时,他将从内存中删除,并且不会永远留在那里(直到用户杀死应用程序)?

最佳答案

你说:

As I understand it, this is because the controller is expecting a Completion Handler callback.

如果 View Controller 没有被释放,那是因为有一个挥之不去的强引用。就你而言,听起来你的闭包保留了那个强有力的引用。为了避免保留强引用,您可以在闭包中使用 [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 被调用)。如果没有,请确保所有异步闭包都使用弱引用,并且没有任何强引用循环。问题的常见来源是重复计时器、观察者等,或传统的强引用循环。 (您可以使用“调试内存图”功能来找出这些强引用的位置,如 this answer 中所述。)

关于ios - 如何摆脱等待完成处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68910714/

相关文章:

ios - NSDictionary 的 NSArray - 当数组中只有一个字典而不是一个对象的数组时返回 NSDictionary

ios - 仅在集成期间出现 Xcode Bot 位码错误

ios - 从字符串中移除 HTML 标签

swift - 代码如果数字大于x,则y = amount

swift - Swift 中的函数参数类型

javascript - 从内部函数中的父作用域访问数组元素

ios - Swift 3 中的闭包速记语法

javascript - 打破一个闭包来向外行解释它

ios - 使用 NSFetchedResultsController 按日期将 CoreData 模型排列成多个部分

ios - block 操作 - 完成 block 返回随机结果