Skip to content

Instantly share code, notes, and snippets.

@rosslebeau
Last active August 28, 2016 21:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rosslebeau/1e19660939132f57ace32efb3f8b51f3 to your computer and use it in GitHub Desktop.
Save rosslebeau/1e19660939132f57ace32efb3f8b51f3 to your computer and use it in GitHub Desktop.
Shows how Swift's instance methods actually all capture self, due to the underlying implementation. Read the whole explanation: http://rosslebeau.com/2016/sneaky-reference-cycles-swift-instance-methods
func weakify<A: AnyObject, B>(obj: A, target: ((A) -> (B) -> Void)?) -> ((B) -> Void) {
return { [weak obj] value in
guard let obj = obj else { return }
target?(obj)(value)
}
}
class Actor {
var action: () -> Void
init() {
action = {}
}
}
class NormalActor: Actor {
deinit {
print("Normal deiniting")
}
func setDefaultAction() -> Void {
action = {
print("Normal action")
}
}
}
class UnsafeActor: Actor {
deinit {
print("UnsafeActor deiniting")
}
func setDefaultAction() -> Void {
action = printThings
}
func printThings() -> Void {
print("Unsafe action")
}
}
class SafeActor: Actor {
deinit {
print("SafeActor deiniting")
}
func setDefaultAction() -> Void {
action = weakify(obj: self, target: SafeActor.printThings)
}
func printThings() -> Void {
print("Safe action")
}
}
// Use this function to create a scope
// All objects created inside should be deallocated at the end of the function
// You will see that UnsafeActor's deinit is never called
func strongReferenceCycleTest() {
let normalActor = NormalActor()
normalActor.setDefaultAction()
normalActor.action()
let unsafeActor = UnsafeActor()
unsafeActor.setDefaultAction()
unsafeActor.action()
let safeActor = SafeActor()
safeActor.setDefaultAction()
safeActor.action()
}
strongReferenceCycleTest()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment