As we know Swift uses Automatic Referencing Counting(ARC) to manage memory of an iOS app.
Whenever an object of reference type is created, ARC allocates a chunk of memory to store the object. Whenever an object is no longer needed, ARC will deallocate the memory so that the memory can be used for other purpose. ARC uses reference count of an object to decide if the class objects can be deallocated or not.
A reference count of an object is the number of other class objects having a strong reference to the current class object. Until there is atleast 1 strong reference to the object, ARC will not deallocate the memory for the object. When there is no strong reference to the current object, the reference count of an object is 0. Now, ARC will deallocate the memory for this object.
Example:
Let us create a Person and a Credit Card classes as shown below
Here we have a class Person with name and credit card as its properties. We also have a second class CreditCard with id and person as its properties.
Person class has an initializer which accepts name as string. Once the person object is initialized, it prints the statement “Person object is initialized“. It also has a deinitializer, which prints the statement “Person object is deinitialized” once the object is deinitalized.
Similarly, CreditCard class has an initializer which accepts id as string. Once the credit card object is initialized, it prints the statement “Credit Card object is initialized“. It also has a deinitializer, which prints the statement “Credit Card object is deinitialized” once the object is deinitalized.
Now, let us create the View Controller class. Let us also create the objects of the class Person and Credit Card inside the viewDidLoad
method of View Controller as shown below.
Once we run the project, we could see that the
- Person object is initialized
- Credit Card object is initialized
- Person object is deinitialized
- Credit Card object is deinitialized
The objects are initialized inside the viewDidLoad
method and ARC allocates the memory to the objects. Once the control comes out of the method, the objects will go out of scope and are deinitialized. If the objects don’t have any other strong reference, ARC will deallocate the memory for the objects.
Now, let us assign the person object to the credit card object’s person property and let us assign the credit card object to the person objects’s credit card property as shown below
Once we run the project, the person and credit card objects are initialized but are not deinitialized as shown below.
As we can see above, both the objects have a strong reference to one another and the objects are not deinitialized. This will result in a poor performance of an app. Sometimes this will also result in a random crash.
In the above diagram, ARC will update the retain count of the person and credit card object to 1 when the view controller is initialized and the objects are created. This is shown in the step 1.
In Step 2, the objects are referenced to one another. ARC will update the reference count of both the objects to 2
In Step 3, the person and credit card objects go out of scope in the View Controller. ARC will reduce the retain count of both the objects to 1.
Since both the objects are referencing one another, the retain count of both the objects will be 1 and it will not be deinitialized. This will result in a Retain Cycle.
Avoiding Retain Cycle
To avoid a retain cycle, one of the variables has to be marked either a weak or unowned. If the variable is a weak/unowned, ARC will not consider it for the retain count.
Let us have the credit card variable in the Person class as weak variable and then run the project.
In the above image, Person object has a weak reference to the credit card and credit card has a strong reference to person object. As a result, whenever a credit card object is deinitialized, person object is deinitialized automatically.
In the above diagram, ARC will update the retain count of the person and credit card object to 1 when the view controller is initialized and the objects are created. This is shown in the step 1.
In Step 2, person object has a weak reference to credit card object and credit card object has a strong reference to person object. Hence the reference count of credit card object will be 1 and the reference count of person object will be 2.
In Step 3, once the control comes out of viewDidLoad
method, the person and credit card objects go out of scope. ARC will reduce the retain count of person object to 1 and credit card object to 0.
In Step 4, Since the reference count of credit card object is 0, ARC will deallocate the memory for credit card object. Since no object is having a strong reference to person object, ARC will deallocate the memory for person object.
Weak and Unowned
As we have seen above, weak and unowned variables do not contribute to the retain count. There are cases where we need to use weak and unowned.
1. Use cases of weak:
- Weak should be used when the lifetime of the other instance is shorter than the current object.
- Weak should be used when we know that the object can become nil at some point in its lifetime.
- A weak variable should always be of
var
and notlet
constants. - Since it can become nil at some time, it should be an
optional
type.
2.Use cases of Unowned:
- Unowned should be used when we know for sure that the variable has a value and it is not nil.
- Unowned should be used when the lifetime of the instance is more than the current object