在 Timer.scheduledTimer 的重复代码中调用异步函数时如何避免内存泄漏?

问题描述 投票:0回答:1

我正在使用启动下载的 SDK,并且如果应用程序在下载完成之前关闭,我会尝试在我的应用程序中构建弹性。如果应用程序在下载仍在进行时关闭,则重新启动应用程序时,SDK 将返回错误。 SDK 函数的示例存根。

self.sdkFunction() { error in 
   guard error == nil else {
      print("some error")
   }
   print("download complete")
}

我利用一些调度组来创建障碍,因为有多个下载,所有下载都必须成功,但我认为这在这里并不特别相关,所以我省略了它。如果下载不成功,则会调用包含此类代码的函数:

DispatchQueue.main.async {
 self.timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { _ in
   print("Timer fired", Date())
   self.sdkFunction() { error in 
      guard error == nil else {
         print("some error")
      }
      print("download complete", Date())
      self.timer.invalidate()
   }
 }
}

这里发生的事情是,每 5 秒,我就会看到计时器被触发。没有打印错误。如果我让应用程序保持打开状态,以便下载可以完成,最终我会看到打印“下载完成”,但我看到它一次打印多次,每次计时器触发一次。

我的假设是,发生这种情况的原因是,当 SDK 的闭包在后台运行时,闭包保持活动状态。最终,一旦下载完成,所有这些都将被解锁并继续打印。在我看来,这就像内存泄漏,因为每次调用闭包时都会分配新的内存空间,并且直到下载完成后才会放弃(如果确实如此)。


我观察到的行为似乎是

sdkFunction
仅在调用时检查下载是否已完成。除非再次调用
sdkFunction
,否则它的闭包不会再次异步执行。但是,如果再次调用并且下载完成,则之前的每个调用都会执行其关闭。不幸的是,我无法修改 SDK 中的代码。

我是否错误地以一种使先前的闭包调用保持活动状态但处于睡眠状态的方式捕获引用?理想情况下,如果计时器的间隔已过,我希望终止每个闭包并回收其内存,这样就不会同时运行多个异步调用。

swift asynchronous swiftui weak-references
1个回答
0
投票

根据您的描述,

sdkFunction
“已损坏”。它应该:

  • 立即调用提供的完成处理程序,指示操作是否完成,或者;
  • 在操作完成或失败之前不会调用提供的完成处理程序,但它应该不需要再次调用
    sdkFunction
    即可执行此操作。

无论如何,你没有内存“泄漏”。是的,重复调用该函数会消耗内存,但是一旦操作完成,所有完成处理程序都会被调用,并且内存将被释放。内存泄漏是指内存被分配但从未释放。

对此你无能为力,因为它是

sdkFunction
保存着对闭包的引用。

© www.soinside.com 2019 - 2024. All rights reserved.