Swift made functions first-class citizens. This means we can get references to functions and assign them to variables or pass them around as parameters to other functions. This is great.
The downside is that, as with any other reference, function references can cause retain cycles. Specially class method references which can easily create strong references to self
.
This is a common problem that many Swift developers have had to learn the hard way [1, 2].
Existing solutions
Swift provides solutions to prevent retain cycles for both class properties (members) and closures:
- Properties can be declared as
weak
optionals. - Closures can use
[weak self]
(alsounowned
) - Static class methods prevent references to
self
However, Swift does not provide any support for weak method references when assigned to strong properties or when passed as arguments.
I would like to submit a proposal to add this feature to the language, but first I thought of pitching it here to see if there was any support or no support at all.
Examples
The following is a basic example of a retain cycle caused by using a method reference which turns into a strong reference to self
:
import Foundation
class MyClass {
var foo: () -> Void = {}
init() {
foo = defaultFoo
}
private func defaultFoo() {
print("Foo Bar")
}
deinit {
print("Released 🎉")
}
}
MyClass().foo()
// prints "Foo Bar" but instance is never released
Proposed (pitched) solution
Add to the language support for using the weak
keyword for method references:
init() {
foo = weak defaultFoo
}
and
setFoo(foo: @escaping () -> Void) {
self.foo = weak foo
}
or
setFoo(weak foo: @escaping () -> Void) {
self.foo = foo
}
What are your thoughts?
I have no idea how feasible this is, but I believe in most cases this could be implemented syntax sugar for a closure with [weak self]
.
Thank you for your time.
Eneko