Last active
July 3, 2018 20:55
-
-
Save rnapier/5b7351988e580e9082a734cd78011061 to your computer and use it in GitHub Desktop.
Laundering retain loops
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
// With functions/methods you can "launder" your code so it doesn't require self references anymore, | |
// but you wind up with retain loops that are very non-obvious. I'm having trouble finding good coding | |
// styles that reliably avoid this kind of problem. | |
class B { | |
// A retain loop waiting to happen | |
var completionHandler: () -> Void = {} | |
} | |
class C { | |
var value = 0 | |
var b = B() | |
var otherValue: Int = 0 { | |
didSet { | |
// Pretty obviously a retain loop, and the required `self` is a warning to that. | |
b.completionHandler = { [otherValue] in self.value = otherValue } | |
} | |
} | |
deinit { | |
print("\(self): DEINIT") | |
} | |
} | |
class C2 { | |
var value = 0 | |
var b = B() | |
var otherValue: Int = 0 { | |
didSet { | |
// This creates a retain loop, but no "self" is required anywhere | |
// Removing the reference to `value` removes the retain loop. So the | |
// caller has to know the internal details the function to know whether | |
// it captures self. | |
func setValue(_ newValue: Int) { value = newValue } | |
func noop(_ newValue: Int) {} // Using this instead does not create a retain loop | |
b.completionHandler = { [otherValue] in setValue(otherValue) } | |
} | |
} | |
deinit { | |
print("\(self): DEINIT") | |
} | |
} | |
// No retain loop | |
var c: C? = C() | |
c = nil // C: DEINIT | |
print("If no DEINIT, this is a retain loop\n----") | |
// Retain loop | |
c = C() | |
c?.otherValue = 2 | |
c = nil | |
print("If no DEINIT, this is a retain loop\n----") | |
// Retain loop, but no "self" is required | |
var c2: C2? = C2() | |
c2?.otherValue = 2 | |
c2 = nil | |
print("If no DEINIT, this is a retain loop\n----") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment