Automatic Reference Counting (ARC) and Memory Management in Swift
Manage your memory better with ARM and Swift.
Join the DZone community and get the full member experience.Join For Free
Memory management is a key factor when we develop apps. If a program is using a lot of memory, it can make apps run slowly or even cause crashes. To handle this in Swift, you can work with Automatic Reference Counting (ARC) to keep your apps memory usage minimal. This doesn’t mean you can completely forget about the memory in your app, but it does take care of most things for you.
It’s important to note that ARC only works when working with classes. Structs and enums are value types and therefore are stored differently in memory than classes, which are stored and passed by reference.
You amy also like: Learn Swift With This Hands-On Tutorial.
Your app could use too much phone memory. This could cause your application to perform badly, crash, or exhibit other unexpected behavior. For example:
Too much phone memory used
In the figure above, we have a viewController, label, or a tableView that loaded in memory, and for some reason, if you forgot to use
dequeueReusableCell, all cells in the array will load all cells, causing your app's memory problem.
Your application could also add something to memory and then never remove it. For example, you have a view controller that shows a popup, which closes and is never removed. If you use that popup so many times, then it uses so much memory and never gets released from memory.
You assign something to memory but unexpectedly remove it from memory. Then, you try to access it or try to get the value of it, which results in a crash because the element doesn’t exist in memory anymore.
These are three different memory problems that are not all but for now, we are going with there.
How These Things Happen
There are two different types in Swift that you need to understand:
Value types: This type can be a String, Int, Stuck, Enum, Array, Dictionary, etc. Each value of an instance (like a String or Int) holds its own value, and if you use it somewhere else, it makes a copy of the variable and passes it around your application.
Reference Types: A class is a reference type. Reference type instances share a single copy of data. So, if you use or pass it around your app, then only one copy exists, and you are just passing a pointer or reference back to your class.
The Job has a default value of 2, and Job first instance created called person. It will have a job of 2.
Now, create a new object called new and assign the previous object to this like as in the code above.
Now change the job of new to 5 and then print the job of both the instance. Both will print the number 5.
This is because the class is a reference type.
When Will Swift Remove a Reference Type From Memory?
This only occurs when there are no more variables pointing to the reference type. Swift uses ARC for this.
How ARC Works
First, create a project with swift language and then select your ViewController.Swift file.
Add the following class to the bottom of your ViewController.swift:
This is a very simple viewController and a class named MyClass. In DidLoad just initiate the class and create a couple more variables pointing to the same class; then, set them all to nil. See the definite function in the MyClass code. This is called right before the object is removed from memory.
So, there is a three-pointer (three reference count for MyClass). Once you nil-all of them, you can see the print statements.
Now, let’s see the second memory problem in which I mention adding something to memory and it never gets removed.
Add the following class to the bottom of you ViewController.swift:
Here, in this example, we are using two classes, Job and Person. The Job class has a variable named person with the type of Person Class. Similarly, the Person class has a variable named job with type of Job Class. We create these properties in DidLoad().
Variables, joe and dev, that we created in DIdLoad() both have their space, memory, and a reference count of 1. Joe is a Person type class variable and dev is a Job type class variable. We now assign Joe dev as his job.
joe?.job = dev
Joe’s job variable will now reference the dev object. Becasue fo this, Job now has a reference count of two, meaning that two objects point to it.
Similarly with dev in the Person Class,
dev?.person = joe
Now, the person variable of dev points to the Person Class, so it also has a reference count of two.
So, what happens if we did use their variables, and we set them to nil?
joe = nil
dev = nil
Still, there is no output from the deallocation print statement in console, and the Job and Person classes can’t be removed from memory because of the job and person variable point to them. This is called the Retain cycle.
In this instance, Apple holds on to these objects and does not let them go with the reference count > 1, as both object reference each other.
Using Instruments Tool to Detect These Problems in Xcode
In Xcode, Go to Product and click on Profile.
Then, a new tool will open named Instruments. Once you've selected that, select Leaks and press Choose.
Then, you can see it point to our simulator and show it next to our app as a target to run.
Then, you just need to tap on the red button and it starts recording.
You can see the red cross sign showing two leaks (just tap on it). Then, you can see what objects are leaking like Job and Person here.
You can look it a different way to like click on Leaks. Then, it will show three options (Leaks, Cycles & Roots, and Call Tree).
Choose Cycles & Roots. Then, a cycle graph will be displayed (Retain Cycle).
This is what the actual problem with memory was. Both classes point to each other.
How to Fix a Retain Cycle:
Use a Weak or Unown reference instead of a Strong reference. A weak or unknown reference does not increment the reference count.
Strong Reference :
It is by default if you make a reference without using weak or unowned then it is a strong reference.
A weak reference's child may or may not exist if the parent is removed from memory. It’s optional it can be set to nil.
In this case, the child definitely exists all the time, but it is removed when the parent is removed, so it is not optional, and we can’t set it to nil.
Let’s fix the Retain Cycle in Code.
As a solution to this, I made the job a weak variable then run the app, so it hits the print the statement for deallocating Job and Person.
Now, if we run the Instrument app then again record our app into it, we can see the green checkmark in place of the red cross. And it's showing no leaks as well
This is how you can track and resolve the Retain Cycle and solve some memory leaks problems.
Published at DZone with permission of Prashant Sharma. See the original article here.
Opinions expressed by DZone contributors are their own.