One of my big fears when I started learning iOS development was dealing with memory management. Why? Because I knew that Objective-C is a superset of C, and I recalled my experience in college of working in C.
In C, you typically have to request that memory be allocated, and when you are done, release the memory. In college, we were not doing anything fancy, but there is a memory lurking in the back of my head of “reference counting“: every time you pointed a variable at a particular value, you incremented a counter, and every time you released that variable, you decremented the counter, and you would know if you could safely deallocate the memory by checking the value of the counter.
Sound complicated? Well, in theory it isn’t. In reality, it was easy to forget to deallocate that memory, and values would sit in memory much longer than they needed to. This is the root of so many of the problems in various early Windows applications, because developers had to work like this.
With the rise of the .NET and Java systems, these issues were mitigated because they used garbage collection. With garbage collection, the system checks on a periodic basis how many references there are to a value, and if the count is none, it gets flushed out of memory. This makes life easy for the developer, but has a very real cost in terms of performance.
Automatic reference counting
In iOS, one of the biggest recent additions for developers is automatic reference counting (ARC). Instead of having to manually add in code to count references and deallocate memory, ARC handles these tasks for you. ARC is not a new idea (Windows COM and classic VB had it), it removes much of the need for thinking about memory management without the performance overhead that a garbage collector brings, and it still allows manual memory management to be done as needed.
Using ARC is easy. The first thing you need to do is to enable it in your project. When you create a project, XCode will ask if you want to turn it on or not. If you are working with existing code, you can convert it to use ARC by going to the Edit menu, and under the Refactor sub-menu you will see “Convert to Objective-C ARC” as a choice. There is also a compiler flag (-fobjc-arc) to enable ARC. You can also go into the build options for a project (select the project, go to advanced build options, and it is near the bottom) like in Figure A to turn it on.
Convert to Objective-C ARC
Within your code, you can now use the “strong” and “weak” keywords in your object instantiation. With these, the compiler understands how to handle the memory for the object. What’s the difference? From the book Learning iPad Programming by Kirby Turner and Tom Harrington (the book I have been using to learn iOS development):
A strong property is claiming “ownership,” and its object is automatically released when the object is no longer referenced. A weak property does not extend the lifetime of the object. In other words, it does not assume ownership, so it is possible that the object is released while the property has a reference to it. However, weak properties are automatically set to nil when the object is released.
The upshot is that the object a weak variable refers to can be released, and if you still attempt to refer to it, instead of the system blowing up, it will simply not work right. Which one you use depends on your needs. By default, variables are marked with strong.
Create a block
Another change is the introduction of the @autoreleasepool block. To use it, just wrap a piece of code in curly braces to create a block, and preface the opening brace with “@autorelease”. This replaces the previous NSAutoreleasePool object. Within this block, all objects that support auto release will be released for you.
By default, the main function in main.m comes with it, and that should be retained. But if you have a piece of code that creates and drops a bunch of objects that support auto release (like a loop with a lot of temporary variables), wrapping it in an @autoreleasepool block is a good way to keep the memory usage low.
One of the neat things (to me, not to everyone) about Objective-C is that it replicates the functionality of other systems within the confines of the C language and a ton of pre-compilation processing. ARC is part of that. Under the hood, it really is not doing anything that programmers were not doing without it.
I’m sure that if you were to peek inside the build process, you would see a pile of code being injected pre-compile that looks like the boilerplate code that iOS developers have been adding by hand. But because it is done like this, the performance is excellent. Working in .NET for a while, I appreciate the garbage collector, but I have also witnessed first hand the performance problems it can bring, and can see the need to be able to manually manage memory as-needed in special circumstances.