iOS: How To Make Weak Delegates In Swift

Here is a common scenario: You have a ViewController with multiple views and you want to delegate some action logic from the View to the ViewController.

For example, let’s say you have a view with a button in it (such as “Sign Up” button in a form), and when the user clicks that button, you want to delegate the logic (validation and API call) for that button to the ViewController to figure out where the user should go (or not) next.

Your code would look something like this:

But there is one BIG problem! Since the View is keeping a strong reference to the ViewController as the delegate and the ViewController is keeping a strong reference to the View, this creates a retain cycle. The ViewController references the View, and the View references the ViewController, ensuring that neither one will ever have the retain count of 0, so neither will be deallocated.

The solution is to make one of them hold on to the other weakly! So how do we do this in Swift? We have to constrain the protocol to only be used by Reference Types by adding the class keyword:

Now, we can say that we want our delegate to be weakly retained:

That’s it!

This is another great example as to why you should attempt to use value types when possible – to avoid this problem. With value types, values are copied, so not memory leaks like the one above can occur. But, of course, we have to work within the Cocoa framework, which includes a lot of subclassing (like that of UIView and UIViewController), so that’s when you need to use the constrained class protocols!

Enjoy the article? Join over 14,500+ Swift developers and enthusiasts who get my weekly updates.

  • Jeremy Pereira

    But with value types, you can’t have a cyclic object graph at all.

  • Nice post. Thanks for this.

    Just as a remark: This can be more elegantly solved using the responder chain. When you set up the target-action using nil as target, the runtime propagates up the responder chain until it finds an instance that implements the method.

    I have put an example of this onto github: