Bad practice: capturing a method reference
You’re more of a video kind of person? I’ve got you covered! Here’s a video with the same content than this article 🍿
This code seems pretty clever, doesn’t it?
Instead of passing a closure to the function sink()
, we’re passing a reference to a method that has a compatible signature.
And since we haven’t written self
anywhere, there should be no risk of creating a retain cycle, right?
But things are unfortunately not as simple as that!
So let’s try and understand what the problem is.
What’s important to recognize here is that handle(value:)
is a method.
This means that it has access to self
:
And so it’s impossible to call a method without providing it with a valid reference to self
.
So what does the compiler do when we pass a reference to that method?
It actually automatically captures a strong reference to self
without telling us!
This means that this seemingly clever syntax is actually equivalent to this other syntax, where the retain cycle becomes much more obvious.
So be careful if you ever find yourself passing method references as arguments: it’s very easy to create a retain cycle!
And unfortunately the compiler will not warn you about the risk…
That’s all for this article: I hope it will help you avoid this tricky pitfall in the future!
Here’s the code if you want to experiment with it:
class ViewModel {
var cancellables = Set<AnyCancellable>()
init() {
publisher
.sink(receiveValue: handle(value:))
.store(in: &cancellables)
}
func handle(value: String) {
// `self` can be used here
}
}