Automatic Reference Counting (ARC)

Swift too uses Automatic Reference Counting (ARC) to keep track and manage all the objects created by the application. This signifies that it handles Memory Management itself and we do not need to take care of it. But there are few situations where we as a developer need to provide few other information, in particularly, the relationship between objects, to avoid Memory Leaks. We would be discussing those situations here.

Reference Counting applies only to the instances of the Class because it is Reference Type. This means that multiple objects can refer to the same object. Where as Structures and Enumerations are Value Types.

Click 2 Origin

Part 1

How ARC works?

Every time we create an instance of a Class, ARC allocates memory that holds information about the Type and Value it holds to. Whenever we assign a class instance to a constant or variable, that particluar constant or variable makes a strong reference to the instance and does not allow it to be deallocated as long as that strong reference exists. ARC keeps track of all the constants and variables currently it is referring to and will not deallocate until the last active reference is released. Once, all the active references are removed, ARC frees up the memory by removing the instance. This ensures that class instances do not take up unnecessary memory when not required.

Let’s see with an Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Employee {
let empName: String
init(employeeName empName: String) {
self.empName = empName
print("\(empName) is being initialized")
}
deinit {
print("\(empName) is being deinitialized")
}
}
var emp1: Employee?
var emp2: Employee?
var emp3: Employee?

In the above Class named Employee, we have an initialiser that sets the instance and prints a message to indicate that initialisation is in process. This also has a de-initialiser that prints out a message when an insance of the Class is deallocated.

Now, let’s create Employee instance and assign it to the first variable emp1.

1
2
emp1 = Employee(employeeName: "John Appleseed")
// Prints "John Appleseed is being initialized"

Now that Employee instance is assigned to the emp1. There is a strong reference from **emp1** to the new Employee instance and ARC ensures that this Employee is kept in memory and not deallocated. Retain Count has increased by 1.

1
2
emp2 = emp1
emp3 = emp1

Now, there are 3 strong references to Employee instance that we created at the beginning. The Retain Count would now be 3.

Now, lets break 2 of these strong references (including the original reference) by assigning nil. The Retain Count would now be 1. Employee instance would not deallocate as there is still exisits 1 last strong reference (emp3).
ARC would not deallocate the Employee instance until the 3rd and final strong reference is broken.

1
2
emp1 = nil // Retain Count would decrease by 1
emp2 = nil // Retain Count would decrease by 1

As soon as 3rd and final strong reference is set to nil, no further strong reference exisits. ARC is now free to remove the Employee instance from the Memory. Pretty Simple Huh!!. Lets dive deep in.

1
2
emp3 = nil
// Prints "John Appleseed is being deinitialized"

What are Reference Cycles?

There could be 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 Refernce Cycle. Let us see this with an example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Employee {
let empName: String
var dept: Department?
init(employeeName empName: String) {
self.empName = empName
print("\(empName) is being initialized")
}
deinit {
print("\(empName) is being deinitialized")
}
}
class Department {
let deptName: String
var emp: Employee?
init(departmentName deptName: String) {
self.deptName = deptName
print("\(deptName) is being initialized")
}
deinit {
print("\(deptName) is being deinitialized")
}
}

In the above code, we have created 2 class. One for Employee and other for Department. Both these classes have strong reference to Department(dept)and Employee(emp) instance respectively. The Retain Count for john and iOS variable would be 1.

1
2
3
4
var john: Employee? = Employee(employeeName: "john")
var iOS: Department? = Department(departmentName: "iOS")
// Prints "john is being initialized"
// Prints "iOS is being initialized"

We would create an Employee and Department instance. This in turn would create a strong reference to john and iOS variable (Image 1–1).

Image 1-1.png

Now assign the two instances together so that Employee is associated with Department and Department is linked to Employee. This would create a strong reference cycle among each other and the Retain Count for john and iOS variable would increase by 1. Retain Count for john and iOS variable is 2 (Image 1-2).

Image 1-2.png
1
2
john!.dept = iOS
iOS!.emp = john

If we set the john and iOS variable to nil , there would still exisits a strong reference between the Employee and Department 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. Such scenarios causes memory leaks in our application (Image 1-3).

Image 1-3.png

How to Resolve these Reference Cycles?

Swift provides two ways of resolving these Strong Reference Cycles: weakand unowned reference.

Weak Reference

Apple Doc states that a weak reference is a reference that does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance. This behavior prevents the reference from becoming part of a strong reference cycle. You indicate a weak reference by placing the weak keyword before a property or variable declaration.

Weak Reference should be used in cases where other instance can be deallocated first without any issue. Confused!!! Let us see this with an example.

Just add weak before emp variable in the Deparment Class. The class would look like the below.

1
2
3
4
5
6
7
8
9
10
11
12
class Department {
let deptName: String
weak var emp: Employee?
init(departmentName deptName: String) {
self.deptName = deptName
print("\(deptName) is being initialized")
}
deinit {
print("\(deptName) is being deinitialized")
}
}

Now, if we create instance variable of Employee and Deparment and assign these instances to each other, Employee instance would hold a strongreference to the Deparment but Department insatance would hold a weakreference to the Employee instance. Retain Count of Employee would be 1where as Retain Count of Department would be 2 (Image 1-4).

1
2
3
4
var john: Employee? = Employee(employeeName: "john")
var iOS: Department? = Department(departmentName: "iOS")
john!.dept = iOS
iOS!.emp = john
Image 1-4.png

Since Employee instance has only one strong reference, as soon as we set the Employee instance to nil, the Retain Count would become 0 and it would be deallocated. Also, the emp variable of the Department would be set to nil reducing the Retain Count to 1(Image 1-5).

1
2
john = nil
// Prints "john is being deinitialized"
Image 1-5.png

Now, the only strong Reference left to the Deparment is from the iOSvariable. Setting nil to the iOS variable would reduce the Retain Count by 1, thus making it 0. Hence, ARC would deallocate the Department instance (Image 1-6).

1
2
iOS = nil
// Prints "iOS is being deinitialized"
Image 1-6.png

Unowned Reference

Unowned reference too does not keep a strong hold on the instance it refers to. However, there is one major difference between Week and UnownedReference. It should only be used when we are sure that both the instance has almost same or more life span. A Weak references must be defined using optional whereas Unowned references must be defined using non-optionaltypes. Both do not increase the Retain Count. Lets see an example.

Suppose we are creating an application for a car Company where they need to keep track of every vehicle sold to the People. We would have Vehicle and Driver Model class.

In the following we have created 2 Class. Owner and Vehicle class. In this Owner may or may not Vehicle but Vehicle to come on Road would need to have a Owner . In such case, the Owner should hold a strong reference to the Vechicle but the Vehicle should just have a unowned reference to the Owner. This is because there is noVehicle which doen’t have an Owner . So, its existence only lies till the Owner owns the Vehicle. But the same doesn’t hold true for Owner.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Owner {
let ownerName: String
var vehicle: Vehicle?
init(ownerName name: String) {
self.ownerName = name
print("\(ownerName) is being initialized")
}
deinit {
print("\(ownerName) is being deinitialized")
}
}
class Vehicle {
let vehicleNumber: String
unowned let owner: Owner
init(vehicleNumber number: String, owner: Owner) {
self.vehicleNumber = number
self.owner = owner
print("\(vehicleNumber) is being initialized")
}
deinit {
print("\(vehicleNumber) is being deinitialized")
}
}

Now, lets create the Owner and Vehicle instance and associate with each other. The Retain Count for the Owner instance is 1 which is held by variable. In case of Vehicle, its just the Owner who is holding the strong reference to it (Image 1–7).

1
2
3
4
5
var appleseed: Owner?
appleseed = Owner(ownerName: "John Appleseed")
appleseed?.vehicle = Vehicle(vehicleNumber: "TE 12 MP 5678", owner: appleseed!)
// Prints "John Appleseed is being initialized"
// Prints "TE 12 MP 5678 is being initialized"
Image 1-7 .png

Its existence is only till the existence of the Owner. Once, the Owner instance is deallocated, the Vehicle instance would automatically be deallocated as there is no strong reference associated to it (Image 1–8, Image 1–9).

1
2
3
appleseed = nil
// Prints "John Appleseed is being deinitialized"
// Prints "TE 12 MP 5678 is being deinitialized"
Image 1-8.png
Image 1-9.png

Part 2

In the First Part, you learned about some fundamental concepts of ARC such as weak, Unowned and how to resolve Reference Cycle using weak and unowned.

In this final part, you’ll learn about one last scenario, where both the properties should have a value and neither property should ever be nilonce the initialization is complete. Also, you would learn how to overcome the Strong Reference Cycle in Closures. Let’s dive straight into it.

Suppose we have a Country and President class. Each of these class stores an instance of the other class as a variable. This means that every Countryshould have a President and every President should be associated with a Country.

To fulfil this requirement without causing a memory Leak, you would need to declare one property (In our case countryPresident in the Country Class) as an implicitly unwrapped optional Property. This can be done by placing the exclamation mark at the end of its type annotation(President!). While for the other, you would need to declare it as an unowned property (In our case country in the President Class).

Suppose we have a Country and President class. Each of these class stores an instance of the other class as a variable. This means that every Countryshould have a President and every President should be associated with a Country.

To fulfil this requirement without causing a memory Leak, you would need to declare one property (In our case countryPresident in the Country Class) as an implicitly unwrapped optional Property. This can be done by placing the exclamation mark at the end of its type annotation(President!). While for the other, you would need to declare it as an unowned property (In our case country in the President Class).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Country {
let countryName: String
var countryPresident: President!
init(countryName: String, presidentName: String) {
self.countryName = countryName
self.countryPresident = President(presidentName: presidentName, country: self)
print("Country is being initialised")
}
deinit {
print("Country is being de-initialised")
}
}
class President {
let presidentName: String
unowned let country: Country
init(presidentName: String, country: Country) {
self.presidentName = presidentName
self.country = country
print("President is being initialised")
}
deinit {
print("President is being de-initialised")
}
}

Because countryPresident has a default nil value, a new Country instance is considered fully initialized as soon as the Country instance sets its countryName property within its initializer. This means that the Country initializer can start to reference and pass around the implicit self property as soon as the countryName property is set. The Country initializer can therefore pass self as one of the parameters for the President initializer when the Country initializer is setting its own countryPresident property. Doing so doesn’t create any strong Reference (Image 2–1).

1
2
3
var country:Country? = Country(countryName: "India", presidentName: "Ram Nath Kovind")
// Prints "President is being initialised"
// Prints "Country is being initialised"
Image 2-1.png

Now, when the country is set to nil, president would also be automatically nullified (Image 2-2).

1
2
3
country = nil
// Prints "President is being de-initialised"
// Prints "Country is being de-initialised"
Image 2-2.png

Try removing unowned from the President Class’s country property. Observe the leak caused when setting country as nil .

Strong Reference Cycle in Closures

A strong reference cycle can also occur if you assign a closure to a property of a class instance and the body of that closure captures the instance. This capture might occur because the closure’s body accesses a property of the instance, such as self.someProperty, or because the closure called a method on the instance, such as self.someMethod(). In either of the case, these access would cause the closure to “capture” self, creating a strong reference cycle.

This strong reference cycle occurs because closures, like classes, are reference types.

Lets see how this strong reference cycle is caused. Suppose you have a PersonClass with firstName, lastName property. You also have a lazy closure property which would return you a full name by combining firstName and lastName. Lets name it as fullName of type ()->String To know more about closure, you can read the Apple Documentation.

The Person Class provides a single initializer, which takes a 2 argument (firstName and lastName). The class also defines a deinitializer, which prints a message to show when an Person instance is deallocated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Person {
var firstName: String?
var lastName: String?
lazy var fullName: ()->String = {
return ("\(self.firstName!) \(self.lastName!)")
}
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
print("Person Class is being initialised")
}
deinit {
print("Person Class is being de-initialised")
}
}

The person variable above is defined as an optional Person, so that it can be set to nil to demonstrate the presence of a strong reference cycle.

The Person instance’s fullName property holds a strong reference to its closure. Also, because the closure refers to self within its body (as a way to reference self.firstName and self.lastName), the closure captures self . This means that it also holds a strong reference to the Person instance. As a result, strong reference cycle is created between the two (Image 2–3).

Even though the closure refers to self multiple times, Swift ensures that it only captures one strong reference to the Person instance.

1
2
3
4
var person: Person? = Person(firstName: "Rahul", lastName: "Singh")
// Prints "Person Class is being initialised"
print(person!.fullName())
// Prints "Rahul Singh"
Image 2-3.png

No message is logged while setting the person variable to nil . This shows that neither the Person instance nor its closure were deallocated. This is because of the Strong Reference Cycle created between the variable and closure (Image 2–4).

1
person = nil
Image 2-4.png

How to resolve the Strong Reference between Class and Closure?

To solve this problem, Swift has an elegent way called as Closure Capture List. You can define the capture list as a part of closure’s definition. A capture list defines a rule to use when capturing one or more reference types within the closure’s body. The way strong reference cycles between two class instances is resolved, ie, you declare each captured reference either to be a weak or unowned , likewise you can choose theses referneces depending on the relationships between the different parts of your code.

Each item in a capture list is a pairing of the weak or unowned keyword with a reference to a class instance (such as self) or a variable initialized with some value (such as delegate = self.delegate!). These pairings are written within a pair of square braces, separated by commas.

The implementation of Person Class remains same to the previous implementation, apart from the addition of a capture list within the fullName closure (Image 2–5). The capture list is [unowned self], which means “capture self as an unowned reference rather than a strong reference”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person {
var firstName: String?
var lastName: String?
lazy var fullName: ()-> String = {[unowned self] in
return ("\(self.firstName!) \(self.lastName!)")
}
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
print("Person Class is being initialised")
}
deinit {
print("Person Class is being de-initialised")
}
}
var person: Person? = Person(firstName: "Rahul", lastName: "Singh")
// Prints "Person Class is being initialised"
print(person!.fullName())
// Prints "Rahul Singh"
Image 2-5.png

In contrast to earlier, this time setting person variable to nil would deallocate the Person Instance and print the desired message (Image 2-6).

1
2
person = nil
// Prints "Person Class is being de-initialised"
Image 2-6.png

Source: Apple Docs and of course Internet 😄

The Playground file can be found here. Feel free to play around with it. Now, poke in if we can use weak instead of unowned in the Closure of the Person Class? If yes, how can this be achieved?

Hope you have liked my tutorial on Automatic Reference Counting.

Do write your comments, if you enjoyed this post. I’d like to grow my readership. Can you help me out by sharing this blog post?

LinkedIn Twitter Facebook

Thx F Sup