This document is for one day in the future, if I find myself with a team of iOS devs and i need to get them to follow some ‘best practices’ when it comes to manual memory management, or hopefully some others out there in the world will find it useful.
Use properties for everything you need your Here’s how I suggest you declare properties, in your header:
@interface MyClass @property(retain) NSMutableArray* myArrayProperty; @end
Notice I don’t bother with ‘nonatomic’ properties. I don’t see any value in typing that unless you’ve got high-performance-critical code, in which case you should probably be re-thinking your algorithm or dropping down to C. Keep the typing to a minimum so we don’t all have RSI when we’re old.
And in your class, lay things out like this:
@implementation MyClass @synthesize myArrayProperty; - (void)dealloc { self.myArrayProperty = nil; [super dealloc]; }
Notice how the dealloc is directly underneath the synthesize declarations: this is so that whenever i create a property, i’m reminded to nil it out in the dealloc. Setting the properties to nil gets the synthesized setter to release any value if necessary. Important: if you don’t use the ‘self.’ then the synthesized setter won’t be used.
One thing worth noting, is that if you’ve got Key-Value Observers, they’ll be notified as you set these properties to nil and be passed a half-dealloced object, which will probably cause crashes. So if you’re using KVO, do the following instead: [myArrayProperty release]; myArrayProperty=nil;
. Having said that, I’ve never found a need for KVO, and recommend against it for this issue. I personally prefer NSNotificationCentre.
If it’s a controller, I don’t really worry about how this exposes all my properties publicly. However, for business logic classes, it’s probably worth declaring the properties in a private category in the .M file instead of in the .H, so that they’re not externally accessible:
// Privates @interface MyClass() @property(retain) NSMutableDictionary* someProperty; @end @implementation MyClass @synthesize someProperty; - (void)dealloc { self.someProperty = nil; [super dealloc]; }
One more thing to keep in mind is that, for simplicity’s sakes, I exclusively use synthesized properties. I’ve simply seen too many bugs in hand-coded getters/setters.
Any static constructors, eg ‘NSArray array’ will return for you an autoreleased object. I always use these in preference to an [[[ABC alloc] init] autorelease], because generally they are cleaner and involve less typing. Plus you don’t have to think about when the value can be released, it’ll just get picked up by the autorelease pool after your function is done with it.
If you want to keep the value around for the duration of your class instance’s existence, do something like this:
self.myProperty = [NSArray arrayWithObjects:a, b, c, nil];
As the saying goes: ‘if you init you own it’. Some classes don’t have static constructors, and you’ll have to resort to allocing/initing instances yourself. In these situations, I always recommend autoreleasing immediately after init'ing, that way i can treat them the same way as I do the static constructor instances. Also, if they’re on the same line, i don’t need to look down the code to see where it is autoreleased.
If you want to keep the value around for the duration of your class instance’s existence, do something like this:
self.myProperty = [[[Something alloc] init] autorelease];
For any IBOutlet properties, I recommend usually using ‘assign’ properties, for these reasons:
Although it has been pointed out to me that in the following cases, you may wish to make them ‘retain’ properties:
If you decide you need to make them retain properties, you’ll have to nil them out in both the dealloc and the viewDidUnload methods.
For new projects, ARC is definitely the way to go. Some libraries that you wish to include won’t be ARC-compatible yet, which is fine: you can disable ARC on a file-by-file basis for those.
To do this, open up your project node in the project navigator, select your target, go into the build phases tab, then expand the ‘Compile Sources’ section. Select all the files you need to disable ARC for, then press enter, and type -fno-objc-arc
into the box that appears.
If you follow these principles, you should be able to keep your memory-management code to a minimum, and focus on the task at hand. If you ever see a ‘retain’ or ‘release’ anywhere, you’re probably making more work for yourself than you need to. Keep it simple!
Thanks for reading! And if you want to get in touch, I'd love to hear from you: chris.hulbert at gmail.
(Comp Sci, Hons - UTS)
Software Developer (Freelancer / Contractor) in Australia.
I have worked at places such as Google, Cochlear, Assembly Payments, News Corp, Fox Sports, NineMSN, FetchTV, Coles, Woolworths, Trust Bank, and Westpac, among others. If you're looking for help developing an iOS app, drop me a line!
Get in touch:
[email protected]
github.com/chrishulbert
linkedin