Creating your first iPhone app can be a challenging experience. For me, it made developing fun again, but only after coming to terms with some concepts that were strange to the Microsoft-wired, C# spewing machine that I call my brain.

1) Memory Management 101

You’ll see that a few of these points deal with memory management. It’s a potentially confusing concept to those of us who have never had to deal with it before. This single concept added probably 20 hours of mind-numbingly tedious debugging to my first app.

Most developers don’t have to worry about managing memory. C#, Java, PHP, Rails, and many more all manage memory for you. What does this even mean? It means that magical memory gnomes automatically “garbage collect” objects that aren’t needed any more. The iPhone SDK doesn’t offer this luxury – you get to play the role of garbage collector.

Let me tell you what will happen if you ignore this concept. Your app will be chugging along nicely until you start watching that embedded YouTube video of your grandma juggling chainsaws when suddenly…crash!

“No biggy”, you say, “I’ll just re-create it and pay close attention to the debugger. It will tell me what I need to do!” So, you start up your debugger, access the video, but nothing happens – it works as expected. “Must be a fluke”, you think to yourself. You continue testing, when …. crash! Out of the blue, the app crashes while testing your tilt-to-scroll functionality. Again, you attempt to re-create, but it’s a no go. Your debugger reads “EXC_BAD_ACCESS” – wow, thanks for the help.

This is a classic case of memory management gone bad. The unfortunate thing with that scenario is that it often won’t start happening until you start testing on devices (the iPhone Simulator is pretty tolerant of unreleased memory – lots more RAM to eat). And when it starts happening, it feels like the gnomes that you used to have working for you are now working against you. Plus, the debugger’s not much help – at least, it won’t tell you where the leaks are happening. You should know, however, that EXC_BAD_ACCESS indicates that you tried to access some memory that has already been released. This either happens because a) You released it and then attempted to access it again, or b) In an attempt to reclaim its quickly depleting memory, the iPhone OS started releasing your views (that’s the default behavior of a memory warning received by a controller).

I could write pages and pages regarding the finer points of memory management, but Apple already has here. You should (must, really) read the entirety of that document. It may sound a bit technical at first, but keep it handy. It will save you hours.

I’ll run down some of the basics as a bit of a primer:

  • Every object has a property called “retainCount” – this is the number of references that have been made in code to the address of your object. This is accessed via [myObject retainCount].
  • As long as this number is greater than 0, that memory stays reserved.
  • A retain count is increased when a “retain” message is sent or when an object is initially allocated.
  • The retain count is decreased by sending a “release” message to your object – [myObject release].
  • When the retain count hits 0, the “dealloc” method of the object gets called and the memory is released (assuming that the “dealloc” method does its job right).
  • A “leak” occurs when an object goes out of scope without being released. You now have no way of releasing that memory…. These are bad and are likely the cause of most major power outages (not really).

Here are some basic rules:

  • Every alloc needs a corresponding release. Make this second nature. Personally, I like to write in the release message at the same time as the alloc message so that I don’t forget. It’s kind of like opening and closing parentheses…
  • In your own class definitions, your dealloc method should release all of the objects it has references to. This includes properties and local variables.
  • When you add an object to an array or dictionary, release it before the original reference goes out of scope. Adding an object to an array or dictionary increases the retain count by 1. This makes sense – the array is taking ownership of the object and retains it so that it doesn’t lose the reference. Later on, when the array is released, all of its objects will be released with it.

So, be a responsible memory manager. It’s not that hard once you get the hang of it. At first, you just need to keep a close eye on your retain counts and use Instruments to help you identify leaks (more on that in a later post).

2) NSAutoReleasePool – Just When Memory Management Was Starting to Make Sense

The points we talked about in Memory Management 101 doesn’t apply 100% of the time. It only applies to objects that are explicitly retained or allocated. So, what happens to everything else? For example:

[NSString stringWithString:@"Hello World"]

There’s no alloc or retain message anywhere in sight, so we don’t have to release it. Yes! You’re off the hook right? Wrong (well, sort of).

See, when an object is created using a class method (as in the above example), it is assumed that the method adds the created object to the most recently created NSAutoReleasePool (on the current thread). “Wait a minute,” you may be thinking, “I didn’t create one of those”. You don’t have to. The application, by default, creates one NSAutoReleasePool on the main thread. When the application exits, it sends a release message to the NSAutoReleasePool, which in turn sends a release message to all of the objects in the pool. Pretty nifty, right?

Most of the time, it’s okay to let small objects such as strings get handled this way. Personally, I still prefer to explicitly allocate and release my strings, just to keep myself in the habit. When should you use NSAutoReleasePool explicitly?

  1. Any time you are performing an action on thread other than the main thread. Threads that get spun off (say, a selector that gets triggered by NSTimer), do not have access to the NSAutoReleasePool on the main thread. Objects that are sent the autorelease message are essentially leaked – there’s no pool to add them to. That is, unless you explicitly create one. Which you should. Just make sure you release it before the method is finished.
  2. Because you prefer to release your objects this way – it’s your style. There’s no problem with creating an NSAutoReleasePool at the beginning of a method and then releasing it before the method ends. In between you can have all manner of autoreleased objects, either because you told them to autorelease or because you used a convenient class method. Just make sure you don’t explicitly release an autoreleased object – you’ll pay later when you attempt to release NSAutoReleasePool.

3) [UIImage imageNamed:@"memoryHog.png"]

Chances are that you’ll need to work with images at some point in the course of your iPhone development. If so, you’ll likely look for the easiest way to grab an image from your application resources. [UIImage imageNamed:] is that method. It’s short, sweet, and you don’t have to figure out the path to your image. Programming bliss…. until you use this method to access a dozen high-res, full-screen images and your app starts crashing (I speak from painful experience).

This method is extremely convenient. And you should use it – sometimes. What isn’t immediately clear about this method is that it loads the image and then caches it in memory in case you need it again. The catch? You don’t have access to the cache where it’s stored – meaning you can’t purge it from memory. It stays there until the application is released.

What should you do instead? It depends, but this is usually a safe bet and gives you finer-tuned control over the release of the image:

UIImage *myImage = [[UIImage alloc] initWithContentsOfFile: @"path/to/my/file"];

The above isn’t a perfect example as you would want to get the path to your resource directory first, but I’ll leave that for you to discover for now. You could alter that method by tacking on an autorelease if you want to use an NSAutoReleasePool.

4) Alt+Double-Click = Enlightenment

Most of the time, SDK documentation is a twisted maze of technical writing. Apple has done a great job of making their documentation easy to access and surprisingly readable. To quickly access the documentation, simply use Alt+Double-Click on a method or class type from XCode.

The documentation will save you many hours of research. Refer to it. Often. If I were smart I would have used it to look up the implications of [UIImage imageNamed] before I learned the hard way.

5) NSLog, a Trusted Friend

In debugging, you will undoubtedly need to output something to the debugger at some point. You can use NSLog to do this. It’s particularly helpful for tracking retain counts and the like. Here’s a simple example:

NSLog(@"%d", [myObject retainCount]);

The first argument is a string format (which you should learn to love), and the following arguments are used to populate the formatted string.

Next Time…

That wraps up part one. Next time, we’ll take a look at instruments and some AppStore tips that will make your distribution easier.