Learn Objective-C: Day 5

Learn Objective-C: Day 5

Tutorial Details
  • Difficulty: Beginner
  • Technology: Objective-C
  • Completion Time: 20 - 30 Minutes
This entry is part 5 of 6 in the series Learn Objective-C

Welcome to part five of this series on Objective-C. Today we’re going to look at memory management, an element of Objective-C (and many other languages) that tends to trip up newer programmers. Most scripting languages (such as PHP) take care of memory managaement automatically, but Objective-C requires that we are careful with our use of memory and manually create and release space for our objects.

It’s good practice to keep track of how much memory your application is using, so you don’t encounter any leaks or hog up the memory on the system. It’s even more important on mobile systems such as the iPhone where memory is much more limited than on a desktop machine.

Two Approaches

In Objective-C there are two methods for managing memory, the first if reference counting and the second is garbage collection. You can think of them as manual and automatic, as reference counting is code added by the programmer and garbage collection is the system automatically managing our memory. An important note is that garbage collection does not work on the iPhone, which is why we will not look at how it works. If you should wish to program for the Mac, then it’s worth looking at Apple’s documentation to see how garbage collection works.

Reference Counting

So, how do we manage our memory in our apps? First of all, when do we use memory in our code? When you create an instance of a class (an object), memory is allocated and our object can now function correctly. Now one little object might not seem that great of a deal, but when your apps grow in size – it quickly becomes an enormous problem.

Let’s look at an example, say we have some sort of drawing app and each shape the user draws is a separate object. If the user has drawn 100 shapes, then we have 100 objects sat in memory. Now let’s say the user starts over and clears the screen, then draws another 100 objects. If we don’t manage our memory properly, we’re going to end up with 200 objects doing nothing more than hogging memory.

We counter this by reference counting. When we create a new object and use alloc, our objects have a retain count of 1. If we call retain on that object, the retain count is now 2 and so on. If we release the object, the retain count decrements back to 1. Whilst the retain count is non-zero, our object will stick around, but when the retain count hits zero, the system deallocates our object – freeing up the memory.

Syntax

There are various methods you can call that will have some effect on memory management. First of all, when you create an object using a method name that contains alloc, new or copy, you take ownership of that object. This is also true if you use the retain method on an object. Once you release, or autorelease (more on that later) an object, you no longer take ownership of that object or care what happens to it.

So, if we alloc an object like so;

myCarClass *car = [myCarClass alloc];

We are now responsible for the object car and we must manually release it later (or autorelease it). It’s important to note that if you were to try and manually release an object that has been set to autorelease, the application would crash.

Since we created our object using alloc, our car object now has a retain count of 1, meaning it will not be deallocated. If were to also retain our object like so;

[car retain];

Then our retain count is now 2. So in order to get rid of the object, we need to release twice to set the retain count to 0. Since the retain count is now zero, the object will be deallocated.

Autorelease and Autorelease Pool’s

When you’ve created a new XCode project, you may have noticed some code that appears by default which creates an autorelease pool, up until now you’ve ignored it – now we’re going to see what it does and where to use it.

The code you’re probably familiar with seeing by now should look like this;

 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 [pool drain];

Note: if you refer to older documentation, you may see the last line as release, rather than drain, this is a newer addition to the language but essentially does the same thing.

By now you should be able to tell to some extent what the code above is doing; it is creating an instance of NSAutoReleasePool called pool, allocating memory for it and then initiating it using the init method.

When we send the autorelease message to an object, that object is then added to the inner most auto release pool (inner-most because pools can be nested within each other – more on that later). When the pool is sent the drain message, then all the objects sent the autorelease message are released, essentially autorelease is deferring the release until later.

This is useful because many methods that return an object, typically return an autoreleased object, which means we don’t have to worry about the retain count of the object we just got given, nor do we have to release it, as it will be done later on.

Nested Autorelease Pool’s

I spoke briefly before about the ability to nest autoreleased pools, but what use is that to us? Although there are several uses, one of the most common uses is to nest an autorelease pool inside a loop that uses temporary objects.

For example, if you have a loop that creates two temporary objects to do whatever it is you wish, if you set those two objects to autorelease, you can use them until the pool is sent the drain message and not have to worry about manually releasing to deallocate. Apple have a great example of when you’d use this kind of nested autorelease pool in their documentation;

void main()
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSArray *args = [[NSProcessInfo processInfo] arguments];
    for (NSString *fileName in args) {
        NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
        NSError *error = nil;
        NSString *fileContents = [[[NSString alloc] initWithContentsOfFile:fileName
																  encoding:NSUTF8StringEncoding error:&error] autorelease];
        /* Process the string, creating and autoreleasing more objects. */
        [loopPool drain];
    }
    /* Do whatever cleanup is needed. */
    [pool drain];
    exit (EXIT_SUCCESS);
}

Source: mmAutoreleasePools

The above example has a bit more than we need, but the structure is there. As you can see, when the application is opened and main is loaded, an autorelease pool called pool is created. Meaning anything autoreleased before the pool is sent the drain message will be assigned to this autorelease pool, unless it is inside an autorelease pool inside this one (sorry if that sounds a little confusing).

Inside the loop, another autorelease pool is created called loopPool. This pool is drained inside the loop, so anything autoreleased inside the loop is released before the loop iterates (or ends).

The inner autorelease pool has absolutely no effect on the outer autorelease pool, you may nest as many autorelease pools as you need. If we used autorelease in the loop above, but did not have a separate autorelease pool, then all the objects we were creating would not be released until the end of main. So if the loop ran 100 times, we would have 100 objects hogging up memory that have yet to be released – bloating our application.

retainCount

Before we wrap up, let’s look at something that could help make memory management an easier-to-swallow chapter. So far when we’ve created objects, we’ve remembered how many references an object has and so on – but we’ve never seen an actual number. For the purposes of education, there is a method we can use to see how many references an object has called retainCount. The way we print a retainCount for an object is like so;

NSLog(@"retainCount for car: %d", [car retainCount]);

retainCount returns an integer, so we use %d to display it in the console. There are rare instances (which we won’t go in to) where retainCount can be wrong and as such should not be 100% relied upon programatically. It is implemented for debugging only, so an app should never go live using the retainCount method.

Wrapping Up

Memory management is a subject that many new programmers find difficult, especially programmers who come from languages that take care of it all for you. We’ve covered the basics, which should be enough to allow you to find your feet and start incorporating memory management in to your apps.

Apple has a fantastic developer documentation library available on their developer website, which I highly recommend you check out if you’re unclear on anything we touched on today. We’ve tried to keep the tutorial short and laser-focused today to help you understand memory management with no other fluff added.

Questions are welcome, as usual.

Challenge

Simply experiment with the console by creating a simple object that contains a few synthesized variables, create a few instances of this class and then check the retain count using the retainCount method. The best way to understand memory management is to fire up XCode and play around with alloc’s and retain’s etc, remember that crashes and mistakes aren’t a brick wall as they’ll ultimately help you avoid the mistakes in future.

Next Time

In the next installment we’ll be looking at categories, a great feature available in Objective-C that can save developers a lot of time and make for more simplistic code.

Series Navigation«Learn Objective-C: Day 4Learn Objective-C: Day 6»

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://mwuk.tumblr.com Mark

    Thanks very much Dan! =D

    Still a couple of weeks behind, but I’m catching up and, thanks to your great tutorials, finally understanding this programming thing ;)
    May even choose to do Obj-C over BASIC for my school course, in which case you really would help me achieve a qualification!

    • http://www.dans-blog.com Dan
      Author

      Glad to hear it Mark, I’d heavily recommend learning Obj-C over BASIC any day of the week!

  • Benjamin

    Hi Dan,

    I’ve learned a lot from your tutorials. They are very good starters before reading the 2-inch thick Objective-C book published by Apple.

    I have a question that is not really related to this tutorial but I really need some help:

    I am developing a scientific calculator for iPhone and I am being stuck at figuring out how to displaying the entire equation prompted by the user… the scenario is as below:

    user inputs: 1, UILabel displays: 1
    user inputs: +, UILabel displays: 1 +
    user inputs: 2, UILabel displays: 1 + 2
    user inputs: =, UILabel displays: 1 + 2 = 3

    Would you please tell me what should I do to display several inputs on the same label?

    Thanks!

  • Oren Raab

    Hi Dan,

    First of all – this is a great tutorial. I was looking for something like this for a long time – all iOS dev/Objective C tutorials I’ve seen so far just assume you know C/C++/OOP and jump right into the Cocoa framework.

    One question about something that bugs me from a “wants to know everything about the programming language” angle. I’ve seen that when a reference to an instance is created it is marked with a glom (*). But it looks like its location differs. On the syntax, it’s sometimes like this:

    data-type* instance-name

    sometimes like this:

    data-type *instance-name

    and sometimes like this (as in the above part):

    data-type * instance-name

    What’s the difference? Is there one? If not, is there a good practice or convention of when to apply which?

    Thanks,

    Oren

    • http://www.twitter.com/AeroEchelon Marvin

      I would love to know the answer to this as well. Something tells me that the location of the ‘*’ doesn’t matter as long that it’s between the variable name and type. Am I right?

    • Oli

      I’m pretty sure it is personal preference, although for me I find it’s good practice to put the * directly after the data type because makes the instance name easier to read. For example

      NSString* stringName;

    • Brian

      As asterisk (or “glom”) between the variable datatype and name indicates it is a pointer and is whitespace independent, meaning It is simply programmer preference.

      As Oli said, I prefer the style of:

      DataType* dataName;

      …because to me, declaring it a pointer is part of the data type.

  • Kamon smith

    Great tutorial ! Thank you.

  • vineeth

    nice tutorial..

  • Farhood

    Great tutorials so far but it would be very nice if you would add more days to this tutorial. Now I’m just keen on learning Objective-C over and over again. I’ll be much appreciated to get more content like using the Interface Builder etc. :)

  • iTAUMA

    How lovely it would have been if we could fire Xcode in a virtual machine just for practice through other OS. Now I just have to wait till I get a mac. :( Nice tutorial :-) Thanks for sharing.

  • GPP

    Heya, thanks for the tutorial. One thing I have been having trouble with is my retainCount keeps saying I have a retainCount of 1, even though the myCar object has been released, followed by a pool drain.

    I even tried putting my NSLog for the Retain Count at the very bottom, right above the return 0; }

    Shouldn’t it be a retainCount of 0?

    write [pool drain]; again just creates a memory leak.

  • Allison

    With the latest XCode and iOS 5, there seems to be a bunch more memory management done by the compiler. In your opinion, does this make memory management out of the equation?

    Automatic Reference Counting
    Automatic Reference Counting (ARC) for Objective-C makes memory management the job of the compiler. By enabling ARC with the new Apple LLVM compiler, you will never need to type retain or release again, dramatically simplifying the development process, while reducing crashes and memory leaks. The compiler has a complete understanding of your objects, and releases each object the instant it is no longer used, so apps run as fast as ever, with predictable, smooth performance.

    P.S. LOVE the tutorials so far. Passed them along to others on my team, as we will be writing mobile apps soon.

  • Allison

    In your challenge you say to create a few instances of a simple class and check retain count. I went back to day 4 and used the CarApp.
    I’ve got: SimpleCar *myCar = [[SimpleCar alloc] init];

    And at the end, before the release, I have: NSLog(@”retainCount for car: %d”, [myCar retainCount]);

    The retainCount is one, which is expected. If I add more SimpleCar’s, the retainCount is always one (which makes sense because there is only one instance of each), so I tried adding: myCar = [SimpleCar alloc], but the retainCount still shows one. I guess I’m missing something there. Can you show me how to get the retainCount to increase? Thanks.

    • John

      As I read through the example I came to the same conclusion. You are checking retainCount on the instance “myCar” and there is only one copy of myCar. You can create myCar2 or myCar3 but you still only have one copy of myCar.

      This makes me wonder about the value of retainCount.

      Can someone please explain?

      Thank you…

  • http://kimuracy007-makinganapplication.blogspot.com/ Cyrus

    This was very confusing to me, but there was one thing I did want to ask you. What is %d, I thought double was %e?
    Or was that a mistake you forgot to check on day 1 for variables?
    I would like an answer, thank-you.

    • RafaelVVA

      %d is for integer

      Why would he print an double when the variable is an int?

  • KimAnnika

    In my Xcode (4.3) the retainCount is unsigned long and to make it work I had to use %lu …

    Otherwise I’d like to say this is the third or so tutorial I’ve tried since I decidec to lerarn iPhone-programming is this is by far the best one :-) It is easy to follow and I escpecially like the example code snippets that are easy to write down and run on my own machine.

    • dipillu

      Hey Kim,

      I had exactly the same issue.The problem arises from the fact that the newer Xcode releases (4.2 till date ) have implemented what is known as Automatic Counting Reference(ARC). This is supposed to aid Data Management and thus relieving the need for release messages and dealloc methods (it actually writes dealloc methods for you!how cool!)

      • Taylor

        Xcode 4.2 includes a menu item to convert targets to use Automatic Reference Counting (ARC), which automates memory management for Objective-C objects. ARC makes memory management much easier, greatly reducing the chance that your program will have memory leaks. First, Xcode reviews your project to determine whether there are items that cannot be converted (and that you must therefore change manually). Then, Xcode rewrites your source code to use ARC.

  • Fergus

    Truly 100% excellent as you state “laser” sharp tutorials. Thanks.

  • Ramprasad Belde

    It is really straight forward.

  • Miguel Sánchez Villafán

    You have an error on the first paragraph of the section “Two Approaches” when you say “the first if reference counting and the second is garbage collection” it should be “the first is reference counting and the second is garbage collection”

  • Miguel Sánchez Villafán

    You have an error on the second paragraph of the sub-section “Reference Counting” when you say “We counter this by reference counting” it should be “We count this by reference counting”

  • Miguel Sánchez Villafán

    You have an error on the third paragraph of the sub-section “Reference Counting” when you say “Whilst the retain count is non-zero” it should be “When the retain count is non-zero”