我试图理解Swift语言中的内存泄漏情况,但有一种情况我仍然想知道。
我创建了一个新的UIViewController并调用fetch函数,将fetch任务存储在一个属性中,但没有启动任务,然后关闭了此UIViewController。
我发现此UIViewController中的***deinit函数未被调用***(内存泄漏)。
func fetchAPI() {
let url = URL(string: "https://www.google.com")!
let task = URLSession.shared.downloadTask(with: url) { _, _, _ in
DispatchQueue.main.async {
print(self.view.description)
}
}
self.vcTask = task
}
但如果我调用resume
方法调用fetch函数,然后再次关闭UIViewController。
我发现这个UIViewController中的***deinit函数被称为***(内存不泄漏)。
func fetchAPI() {
let url = URL(string: "https://www.google.com")!
let task = URLSession.shared.downloadTask(with: url) { _, _, _ in
DispatchQueue.main.async {
print(self.view.description)
}
}
self.vcTask = task
task.resume() // start downloading
}
现在我认为如果我在UIViewController的属性中存储一个任务,并且在回调中使用self
,它将创建一个导致内存泄漏的循环。
但是当我调用task.resume()
时为什么在这种情况下内存没有泄漏?
2条答案
按热度按时间y1aodyip1#
一个un-
resume
d任务将永远不会执行它的完成处理程序,因为它永远不会完成。因此,任务及其处理程序将保留在内存中。我们不知道
URLSession*
的内部实现,但框架在完成处理程序执行后丢弃它们似乎是明智的,这将打破保留循环,并允许视图控制器被释放。您可以通过在完成处理程序和deinit方法中添加额外的日志记录来确认这一点-我希望视图控制器在完成处理程序运行之前不会被释放。
ca1c2owp2#
(加上@jrturton的答案,答案100%正确)
这行代码
强烈捕获
self
,导致内存泄漏。避免这种情况的一种方法是将捕获更改为
weak
,如下所示:或者,尝试将
self.vcTask = nil
添加到ViewController的viewDidDisappear
方法以手动打破循环。