Nowadays, more and more apps are shipped to an app store, to make your app stand out in the crowd, your app should be consuming less memory while providing faster and better user experience.
Apple provides great tools along with the Xcode to profile the application for finding the memory leaks and other great bug detection tools. Today I will guide you through small sample demo how you can detect the leaks in the application.
Steps to follow:
1 ) First Download sample project link provided at the end for the debugging the leaks in the sample application.
When you run the application, you will find that memory consumed by an application is increasing when you follow the below steps:
- Go to tableview containing the list of an image.
- Click on the image to see the details.
- Go back to table view of the images.
- Follow this step for around 30 - 40 times.
You can see the memory usage of your application is increasing continuously.
To track down the memory issues in your application, you can use allocations tool provided by apple. Let’s start with a sample application to get familiar with it.
2 ) Prepare your application for catching memory leaks.
Apple provides a great tool called instruments for finding the memory leaks in an application. To use it,
- Select Product > Profile in your Xcode.
- Select the Allocations in the profiler.
- Press record button provided inside the window. This will start your application normally.
3 ) Analyse your application for the memory leaks.
Now start using the application as normal. To get the bug of leaks user should repeat the step in an application which causes the memory to grow.
In our case when you go back and forth from the SecondViewController
to DetailViewController
memory grows so much. Do it around 30 - 35 times, then click the Pause button.
You will see the graph like shown below, where it is continuously growing. It means that there is a memory leak in the application. So let’s find it out.
There are several things to keep in mind.
1. Here, we will select the Details > Call Trees, which will show you the list of the lines with memory consumption.
Select the line with most Bytes used. See below image for the same
2. You can see many system calls are there which are not useful for our purpose. You can simply hide those calls from a list by checking the option of Hiding System Libraries in Display Settings.
3. Also, assure that Record reference counts are checked, this will be useful for the tracking down the leaks.
Now, Call Tree will be showing the Tree View with the familiar method like below.
Now select the line to go into the details for the memory leaks, will lead to code inside the editor that might be causing the memory issue. In the following case, code snippet shown is found as below.
For more assurance select the Details > Statistics and search for the, DetailViewController
where we are facing the issue.
As you can see in above image 27 instances are created, but no instance is released. Select it to get the list of the instances for it.
Select any of them since all are of the same kind to track down the problem. When you will select any of them, It will show below the screen.
Make sure you have selected Unpaired for better filtering of the list. Find the line where the Responsible Library is declared other than UIKit and whose Event type is "retain" and not associated Release is created. Since there
must be every Retain to be Released for every Responsible Caller.
In our case, it's on line 129 where Retain has no associated Release type. It point to viewDidLoad()
method in DetailViewController
. So we are now sure of the memory problem created on the viewDidLoad()
If we observe the code closely, we can infer that, data variable is loading the file from the path inside the viewDidLoad()
method. When the DetailViewController
is popped it automatically gets released.
Let’s take a look at line self.imageView.delegate = self
,
It is suspicious because we don’t know the what variable imageView is holding. Go to CustomImageView
class.
So here the problem is, variable var delegate
is of kind AnyObject?
and by default it is strong.
We are assigning the DetailViewController
object to this delegate
which is self
. This is creating the strong reference cycle between the DetailViewController
and CustomImageView
.
Since the CustomImageView
is a child of the DetailViewController
it should be defined as a weak variable to solve the memory leak as the general practice. So Let’s correct it and rerun the app.
When we again run the application, our problem is solved.
Download sample application here