函数内部函数保留周期

Function inside Function retain cycle

我想知道在以下情况下如何避免保留周期:

private func setupDismissCallbacks() {

  // inner func     
  func dismiss() {
     self.videoExporter?.cancel()
     self.rootViewController.dismiss(animated: true, completion: nil)
     self.delegate?.childCoordinatorDidFinish(self)
  }

  // first clousre       
  saveModalViewController.onButtonDismiss = {  [weak self] in
     // not really using `self` here
     guard let self = self else { return }
     dismiss()
  }

  // second clousre  
  saveModalViewController.onDimmedAreaDismiss = { [weak self] in
     // not really using `self` here
     guard let self = self else { return }
     dismiss()
  }

}

我有一个函数 setupDismissCallbacks,它监听来自 saveModalViewController 自身 属性 的两个回调。 dismiss()setupDismissCallbacks 中的一个内部函数,我用它来访问 self 值。

但是在闭包 onButtonDismissonDimmedAreaDismiss 中,我无法访问 self 来调用 dismiss,而且我无法将 [weak self] 添加到 dismiss 函数,因为它是一个函数。

如何验证 dismiss 中的调用不会导致保留循环?

@Alexander 在评论中解释了这个问题:

Your inner function captures self. Your two closures capture that inner function (including the context it encloses over, which includes self). Since your two closures are strongly referenced by saveModalViewController (which I assume is strongly referenced by self), you have a retain cycle.

您可以通过不让 dismiss 捕获 self 来打破这个循环。将 SaveCoordinator 传递给 dismiss:

private func setupDismissCallbacks() {     
  func dismiss(_ coordinator: SaveCoordinator) {
     coordinator.videoExporter?.cancel()
     coordinator(animated: true, completion: nil)
     coordinator.delegate?.childCoordinatorDidFinish(coordinator)
  }

  // first clousre       
  saveModalViewController.onButtonDismiss = {  [weak self] in
     guard let self = self else { return }
     dismiss(self)
  }

  // second clousre  
  saveModalViewController.onDimmedAreaDismiss = { [weak self] in
     guard let self = self else { return }
     dismiss(self)
  }

}

只需将闭包分配给局部变量即可。那时,提取 dismiss 是没有意义的,所以直接内联它:

private func setupDismissCallbacks() {     
    let dismissCallback: () -> Void = {  [weak self] in
        guard let self = self else { return }
        self.videoExporter?.cancel()
        self.rootViewController.dismiss(animated: true, completion: nil)
        self.delegate?.childCoordinatorDidFinish(self)
    }

    saveModalViewController.onButtonDismiss = dismissCallback
    saveModalViewController.onDimmedAreaDismiss = dismissCallback
}