Last active
May 15, 2020 08:21
-
-
Save 4np/fd6981df487f5ed42426a9f07c1db32f to your computer and use it in GitHub Desktop.
A Swift Playground demonstrating why you need to again weekly capture self in nested closures after unwrapping self.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Cocoa | |
class TestClass { | |
var name = "" | |
var block1: (() -> Void)? | |
var block2: (() -> Void)? | |
var retainCount: Int { | |
CFGetRetainCount(self) | |
} | |
init() { | |
print("Initializing: \(retainCount)") | |
} | |
func foo() { | |
print("Starting Foo: \(retainCount)") | |
block1 = { [weak self] in | |
print("Inside block 1: \(String(describing: self?.retainCount))") | |
self?.block2 = { | |
// `self` is still weekly captured from `block1`. | |
print("Inside block 2: \(String(describing: self?.retainCount))") | |
} | |
// Execute block 2 | |
self?.block2?() | |
print("Finishing block 1: \(String(describing: self?.retainCount))") | |
} | |
// Execute block 1 | |
block1?() | |
print("Finishing Foo: \(retainCount)") | |
} | |
func bar() { | |
print("Starting Bar: \(retainCount)") | |
block1 = { [weak self] in | |
// Unwrapping `self`. | |
guard let self = self else { return } | |
print("Inside block 1: \(self.retainCount)") | |
// As you now have a strong reference to `self`, you to again weekly capture `self` in nested closures. | |
self.block2 = { [weak self] in | |
print("Inside block 2: \(String(describing: self?.retainCount))") | |
} | |
// Execute block 2 | |
self.block2?() | |
print("Finishing block 1: \(self.retainCount)") | |
} | |
// Execute block 1 | |
block1?() | |
print("Finishing Bar: \(retainCount)") | |
} | |
deinit { | |
print("Deinitializing: \(retainCount)") | |
} | |
} | |
var testClass: TestClass? = TestClass() | |
testClass?.foo() | |
testClass?.bar() | |
testClass = nil |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In
foo()
you weekly captureself
in block1, and you can just continue to use it in the nested closureblock2
. Inbar()
you weekly captureself
in block1, but as you unwrapself
you need to again weekly captureself
in block2 as you now hold a strong reference toself
.Executing this playground demonstrates that, as in both cases
TestClass
is being properly released andTestClass
deinitializes:If you wouldn't weekly capture self in
bar()
'sblock2
, you would have a retain cycle because you are still holding a strong reference toself
and the class is never deinitialized. Hence, a memory leak: