Reputation: 5896
I was wondering how to avoid retain cycle in the following scenario:
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()
}
}
I have a function setupDismissCallbacks
that listens to two callbacks from a saveModalViewController
self property. dismiss()
is an inner function inside setupDismissCallbacks
that I'm using to access self
values.
But inside the closures onButtonDismiss
and onDimmedAreaDismiss
I don't access self to call dismiss
, and I can't add [weak self]
into dismiss
function because it's a function.
How can I verify that the calls inside dismiss
won't cause retain cycle?
Upvotes: 1
Views: 763
Reputation: 63271
Just assign your closure to a local variable. At that point, extracting out dismiss
is pointless, so just inline it:
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
}
Upvotes: 2
Reputation: 154603
@Alexander explained the issue in the comments:
Your inner function captures
self
. Your two closures capture that inner function (including the context it encloses over, which includesself
). Since your two closures are strongly referenced bysaveModalViewController
(which I assume is strongly referenced byself
), you have a retain cycle.
You can break this cycle by not having dismiss
capture self
. Pass the SaveCoordinator
to 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)
}
}
Upvotes: 1