Delegate Retention Cycle

Introduction

Welcome to Lesson 2 of Swift Memory Management. You will discover a potential retain cycle that might occur while using the delegate pattern.

Problem

Why delegate should be weak var

Design Delegate Pattern

Let us create a classic structure: the protocol, the delegator, and the delegate.

Design Protocol

  1. protocol SendDataDelegate {}

Design Sender/Delegator

  1. class SendingVC {
  2. var delegate: SendDataDelegate?
  3. deinit {
  4. print("Delegator gone")
  5. }
  6. }

Design Receiver/Delegate

  1. class ReceivingVC: SendDataDelegate {
  2. lazy var sendingVC: SendingVC = {
  3. let vc = SendingVC()
  4. vc.delegate = self
  5. return vc
  6. }()
  7. deinit {
  8. print("Delegate gone")
  9. }
  10. }

Important: The closure init method is used with the lazy keyword from 3003_lazy_init_closures. You may not interact with self while creating a brand new property since it is not initialized. However, lazy allows since the property is initialized only after self has been created.

Create Instances

  1. var receivingVC: ReceivingVC? = ReceivingVC()
  2. receivingVC?.sendingVC // lazy born

Let us visualize the relationship.

Delegate Retain Cycle - 图1

There is a retain cycle. Even if you set recevingVC as nil, there is a reference count for both ReceivingVC and SendingVC from each other.

  1. receivingVC = nil
  2. // not deallocated

Deallocate

Make one of the relationships/references as weak.

  1. class SendingVC {
  2. weak var delegate: SendDataDelegate?
  3. ...
  4. }

However, as soon as you work with weak which only applies to reference types, the compiler forces you to indicate the protocol as a different animal

  1. protocol SendDataDelegate: class {}

Let us visualize the relationship.

Delegate Retain Cycle - 图2

Let us deallocate

  1. receivingVC = nil
  2. // "Delegate gone"

Delegate Retain Cycle - 图3

Notice that the SendingVC object also has been deallocated since it no longer has a reference from the ReceivingVC object.

Rules

  • A weak reference allows the referencing object to becoming nil (this happens automatically when the referenced object is deallocated)
  • Based on the rule above, the referencing object/variable must be optional

Source Code

5002_delegate_retention_cycle.playground

Conclusion

You’ve learned how to spot a retain cycle within the delegate pattern. You may wonder which variable should be set as weak. The #1 rule is, a weak property has a reference to a class object which more likely to stays longer, and eventually has greater importance. For example, if the SendingVC object has a weak reference from the recevingVC property, the object will be deallocated immediately since the reference count is zero.

In the following lesson, you will discover the pitfall of using closures due to the unique behavior you’ve learned in Chapter 3, 3004_capture_lists

Note: Learn Swift with Bob is available on Udemy. If you wish to receive a discount link, you may sign up here.