Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Automatic Reference Counting (ARC) and Memory Management in Swift

DZone 's Guide to

Automatic Reference Counting (ARC) and Memory Management in Swift

Manage your memory better with ARM and Swift.

· Web Dev Zone ·
Free Resource

floppy-disk-red

Get ARC to work for you

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.

Memory Problems

  • 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

    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:

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

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

Working with reference types in Swift

Working with reference types in Swift

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:

Adding class to ViewController

Adding class to ViewController

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:

Adding class to viewController

Adding class to ViewController

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.

Reference counts for Job and Person classes

Reference counts for Job and Person classes

So, what happens if we did use their variables, and we set them to nil?

 joe = nil


 dev = nil 

Strong reference between Person and Job classes

Strong reference between Person and Job classes

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.

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.

Product -> Profile in XCode

Product Profile in XCode

 Then, a new tool will open named Instruments. Once you've selected that, select Leaks and press Choose.

Selecting Leaks and pressing Choose

Selecting Leaks and pressing Choose

 Then, you can see it point to our simulator and show it next to our app as a target to run.

Pointing to the simulator

Pointing to the simulator

 Then, you just need to tap on the red button and it starts recording.

Beginning recording

Beginning 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.

Job and Person leaking

Job and Person leaking

You can look it a different way to like click on Leaks. Then, it will show three options (Leaks, Cycles & Roots, and Call Tree).

Displaying leaks, cycles & routes, and call tree

Displaying leaks, cycles and routes, and call tree

Choose Cycles & Roots. Then, a cycle graph will be displayed (Retain Cycle).

Cycle graph

Cycle graph

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.

Weak 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.

Unowned Reference:

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.

Fixing the retain cycle

Fixing the retain cycle

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

No leaks!

No leaks!

This is how you can track and resolve the Retain Cycle and solve some memory leaks problems.


Related Articles

Topics:
arc ,memory management ,swift ,memory leak ,web dev ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}