Swift 4.0: Automatic Reference Counting (ARC) — Part 2

Rahul Singh
Swift India
Published in
6 min readMay 22, 2018

Welcome back to Part Two of this tutorial on Automatic Reference Counting! 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 nil once 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 Country should 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).

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 1–1).

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

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

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

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 Person Class 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.

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–1).

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

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

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–2).

person = nil
Image 2–2

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–3). The capture list is [unowned self], which means “capture self as an unowned reference rather than a strong reference”.

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–3

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

person = nil
// Prints "Person Class is being de-initialised"
Image 3–4

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

--

--