Developer's Blog

[iOS Development Tips] The true terror of memory leaks

For all of you who are developing for iOS, I am quite sure you check for memory leaks.
How are you checking for memory leaks? You are probably using the method below.

– Use Static Analyzer

– Instruments Leaks Template

However, did you know even if you use these, there is still a chance that there will be some memory leaks that could not be found?

Are you applying a number of “View” with “addSubview:”?

Whether you can actually call this a memory leak may seem a little questionable, but I will call this a memory leak as it does take more and more memory without the intent of the developer.

A really difficult to spot memory leak is one that occurs when using “addSubview:” with “view”.

Please take a look at the code below. It is executed when a specified button is pressed by an installed method of a specified UIViewController.

- (void)addLabel {
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 100, 300, 60)];
    label.text = @"test";
    [self.view addSubview:label];
    [label release];
}

 

The UILabel generated by alloc is properly released in the last method. If you just look at this there are no problems. A leak is not detected in Static Analyzer or in Leaks Template.
However, what would happen if this method was repeated many times?

Worked it out?

“addSubview:” retains the UIView passed as an argument by the receiver. When the above (void)addButton method is repeated multiple times, only the value in the same location is applied for UILabel.
When the applied View has shadows attached, the colour of the shadow becomes dark so it is easy to spot, but with the example above it is very difficult to spot with your eyes so please be careful.

Counter-measures

This problem can be easily prevented. Just call removeFromSuperview before addSubview for view.
The counter-measure for the previously shown example can be viewed below.

- (void)addLabel {
    /* Remove beforehand if applied label already exists */
    UIView *oldLabel = [self.view viewWithTag:TEST_LABEL_TAG];
    [oldLabel removeFromSuperview];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 100, 300, 60)];
    label.text = @"test";
    label.tag = TEST_LABEL_TAG; // defined tag
    [self.view addSubview:label];
    [label release];
}

 

In this example I have used tag to take a reference to the applied Label. When the applieed label is maintained as an instance variable, it can be removed without the use of tag. The viewWithTag: return value will become nil at the first calling of the addButton method, but in Objective-C, even if a message is read with nil nothing will happen so there are no problems with this course of action.

How to find out the risk of a memory leak when using addSubview:

The only way I can think of is as below:

1. Check whether the total memory usage has increased with the Instruments Allocations Template.

2. Check whether there is any increase with any operations with specific class objects(UI Label in the example).

It is very difficult to detect the problem when only a small amount of memory is increasing with method 1.
When using method 2, you can input a class name into the Instruments search field and narrow the results down, and then check whether the number of #Living is appropriate, but it is difficult to narrow down all the class names that should be narrowed down to list them up and check them.

As it is a difficult problem to spot, I usually investigate whether it is necessary to call removeFromSuperview before calling addSubview:. In order to avoid misses, it is generally best to call removerFromSuperview.

Summary

So that is the end to my introduction about memory leaks that are difficult to detect using memory leak tools. There are probably many other examples of hidden memory leaks out there. I will continue to open my eyes to all the finest details so that memory leaks do not occur so that I can continue to create apps without memory leaks.

Please join us on Facebook for Sleipnir Mobile!


Please follow us on Twitter!

Facebook Comments