Memory Management with ARC and Avoiding retain cycles with Weak and Unowned in Swift iOS

In this article, I will try to realistically summarize memory management with ARC in the last few days, I was doing more research on Swift ARC memory management in iOS.How ARC works in Swift?,How to find retain cycle?. Weak and Unowned keyword avoid it. It was a difficult subject for me to understand in Swift. Therefore, I decided to go a little deeper into memory management.
What is memory Management?

Memory management is a core concept in any programming language when developing applications. If a program is using too much memory it can cause your device to run slowly or even cause a crash.

Memory management is the process of controlling the memory of a program. It is important to understand how this works, otherwise you are likely to run into random crashes and minor bugs.

How ARC Works?
ARC(Automatic Reference Counting)
Swift introduced a powerful feature called Automatic Reference Counting (ARC) which handles most of an app’s memory management.
ARC is a compile time mechanism to manage the memory of an application.
ARC keeps track of the reference counting of the object.when reference counting become zero then ARC release the object and call deinit()
👉ARC automatically frees up memory used by class when instance haven’t strong references.
👉ARC only works for reference types, specifically class instances.
👉Structures and enumerations are value types and not stored and passed by reference. There are stored on stack.

Here’s an example of how Automatic Reference Counting works. When you start working with objects, you will notice an interesting thing.
Every time you create a new instance of a class, ARC is responsible for allocating and deallocating the memory that objects use. 

In the above code, we have created Employee class.We would create an instance of Employee class has initialized.The Reference Count for instance variable would be 1.
Because there is at least one strong reference, ARC makes sure that this Employee is kept in memory and is not deallocated.

If you assign the same Employee instance to three more variables, three more strong references to that instance are established, Every Time Automatic reference counts one increment.
  1. reference1 = objReference //ARC 2
  2. reference2 = objReference //ARC 3
  3. reference3 = objReference //ARC 4
There are now four strong references to this single Employee instance.
If you break three of these strong references (including the original reference) by assigning nil to three of the variables, a single strong reference remains, and the Employee instance is not deallocated, ARC value is decreased.
  1. objReference = nil //ARC 3
  2. objReference1 = nil //ARC 2
  3. objReference2 = nil //ARC 1
ARC does not deallocate the Employee instance until the fourth and final strong reference is broken, at which point it’s clear that you are no longer using the Employee instance:
  1. reference3 = nil. //ARC 0
  2. // Prints "Pankaj is being deinitialized"

Strong Reference Cycles (retain cycle)

We will see a scenario where two class instance holds a strong Reference to each other and there is no way for the system to deallocate them. This means that the Retain Count of both the class insance would never come down to 0. This is known as Strong reference cycle.

In the example above, there are two simple classes called Employ and Manager. Each classes has an optional property which has the type of the other class. As you can see in the code, those properties are assigned each other’s instance after its initialization.Current relationship between those two can be described as the picture below.

strong reference

I created the instance objEmployee line 27, created an instance of objManager at line 28, assigned 
objEmployee!.manager = objManager and 
objManager!.emp = objEmployee 

If we set the objEmployee and objManager variable to nil  line 29 & 30, there would still exisits a strong reference between the Employee and Manager 
instance which now cannot be broken. Retain Count now would be 1. 
Since, the Retain Count did not drop to 0, ARC did not deallocate the instances. 
No outputs about deinitialization.
What happend?

Employee has strong reference to Manager.
Manager has strong reference to Employee.
!!! This is strong reference cycle. !!!
!!! This scenario is called Memory Leak. !!!
👉Swift by default internally creates a strong refernce cycle. 

How to Avoiding these Reference Cycles?
Swift provides two ways to avoid strong reference cycle. 

  1. weak reference
  2. unowned reference.
A weak reference doesn’t have a strong reference to the instance. In other words, it doesn’t increase the strong reference count of the instance. Thus, it is not really in the lifecycle management of the instance if you use the weak keyword. Now let’s modify the previous example.

In relation to our code, the Employee class has a strong reference to the Manager class, but the Manager class has a weak reference to the Employee class.Notice Manager class’s emp property is declared with a weak keyword this time.This change can be described as below.

Weak reference

Weak references are created using the keyword weak before its declaration.
weak var emp: Employee?
This scenario a little change makes a big difference When you set nil to the variable and you can see that the deinit () method is called.

objEmployee = nil
objManager = nil
// deinit() call

Why use weak reference?

Memory management is a core concept because you are not creating a desktop or web app, your app is not running on the server. Your app is running on a small mobile device that has limited memory and our app works within that memory.
If your app has all these strong reference cycles, then its bad because there are objects in your memory which are nothing used, but they are still occupying space, so it is very important that you use the weak keyword and make sure there are no strong reference cycles.Weak references should be used to avoid retain cycles.
Unowned reference always have a value. ARC never sets value of unowned reference to nil. Unowned reference defined using nonoptional types.

there is a big difference between Week and Unowned Reference. A Weak references must be defined using optional whereas Unowned references must be defined using non-optional types. Same as a weak reference, an unowned reference doesn’t increase the reference count. Lets see an example.

unowned reference
Next scenario to set up the interdependency between the two classes, the initializer for Manager takes a Employee instance, and stores this instance in its emp property.
The initializer for Manager is called from within the initializer for Employee. However, the initializer for Employee cannot pass self to the Manager initializer until a new Employee instance is fully initialized, as you can see the code 
 init(depart:String,emp:Employee) {
      self.departman = depart
      self.emp = emp
        print("\(departman) is being initialized")

This process is called Two-Phase Initialization.

Hope you all enjoyed!
Subscribe to AppCodeZip to get notifications about new stories.
Thanks for reading!!


Post a Comment