iOS 5 is coming soon, and introduces ARC. ARC will make Objective-C memory management significantly simpler. But, it will be a long time before iOS 5 is ubiquitous, and I’m not sold on the subset of ARC that will be available for iOS 4. So, in the meantime, I thought people might benefit from seeing the conventions I use to keep Objective-C memory management simple. Most iOS developers probably already follow something close to this, but it doesn’t hurt to have it written out.
If you follow these five simple rules, you should pretty much never get a memory leak or a crash from over-releasing.
1. Always declare @properties for your object instance variables
If you’re putting an instance variable on a class and it’s an object, declare a property for it.
1 2 3 4 5 6 7 8 9 10 |
|
By default, you should always declare your object properties as retain
.
If you’re declaring a property for an object that’s expected to be immutable, but has a mutable subclass (for example, if you’re declaring an NSArray
property, which has the NSMutableArray
subclass), declare it as copy
instead of retain
.
If you’re declaring a property for an object that is guaranteed to be retained elsewhere (for example, a delegate, or something that you’re also storing in an array and just need a convenient shortcut to), you can declare it assign
. Be very careful with this though. If you’re unsure, just do retain
or copy
.
You’ll also need to @synthesize
all these properties in your @implementation
:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Finally, you’ll need to release all of the retain
and copy
properties (but not the assign
properties) in your dealloc
. This is the only place in your code where you should refer to your properties without self.
(which means you’re actually accessing the instance variables rather than the properties).
1 2 3 4 5 6 7 8 9 10 11 12 |
|
2. Always use self
when accessing a property
If you don’t use self
, you will be accessing the underlying instance variable directly, rather than going through the @synthesized getter/setter.
1 2 3 4 |
|
If you skip the @synthesized getter/setter, you skip the memory management rules you defined in your @property
, which will lead to problems. The only exception to this is mentioned in rule 1: in your dealloc
method, when releasing the object.
3. Make sure all newly-created objects are autoreleased
There is a bit of disagreement on the community on this one, but I have yet to hear a compelling argument for all but the most extreme cases, so we’ll go with the side that makes life easier. Whenever you create a new object, make sure it is autoreleased.
The convention for this is as follows: all methods that return objects return autoreleased objects, unless the method name starts with init
or copy
. For example:
1 2 |
|
If you create an object with a method that starts with init
or copy
, make sure you explicitly tell it to autorelease:
1
|
|
This will save you a lot of headaches. Any objects that you don’t want to keep will be released automatically. Any objects that you do want to keep should be assigned to a property, and since the property is retain
or copy
(as mentioned in rule 1), they will be retained and kept automatically.
4. Never call retain
on anything
The method retain
is not called once in all the lines of Objective-C code in my current code base. If you find yourself needing to explicitly retain an object, create a retain
or copy
property for it instead (as mentioned in rule 1) and assign it to that property.
5. Never call release
on anything (except in dealloc
)
If you’re following rule 4, there should never be a time when you explicitly need to release an object, except in your class’s dealloc
method (as mentioned in rule 1).
If you follow all these rules, you should never have to think about memory management. If you deviate from any of them, you could end up in weird tough-to-debug situations, so try your hardest not to. If you find yourself in a situation where you think you absolutely need to deviate, write a comment on this post explaining your situation, and I’ll see if I can help.