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
    }
}
Previous
Previous

How about 5 new tips you can start using today? 💡

Next
Next

Here are 5 tools that will improve your iOS project 🛠