iPhone Programming Part 2 : Objective C Memory Management
In your application you should always know about when objects are allocated and when they will be released, otherwise your application will have memory leaks, which will on low memory systems like iPhone lead to an application crash.
There are two possibillities how to handle object allocations. The first way is to manually allocate and release objects. The other -more tempting- way is to let the system release it for you, but then sometimes your application will hang or temporarly stick in memory.
The creators of Objective C may thought : “Why not combine both techniques to get benefits of both of it?”. Well, sometimes I think they may have missed the goal. Objects are deallocated when you don’t want it, and sometimes they will be deallocated twice, which results in an application crash. Or the will not be deallocated when you want it, so it results in memory leaks (which will end the application on iPhones with : result 101)
But how does an autorelease function? All objects derived from a general object will have the ability to count the references. If you create an object the reference will be 1. If you assign this object to a variable the reference counter will be increased by one. If you reset this variable to any other object (also NULL, nil, or what ever) the reference counter will be decreased by one. If all references are lost (counter is zero) the object is not referenced anymore and will be released.
Therefore our focus is about these methods of NSObject :
Example 1
Objects you allocate with alloc should be released with release and then grounded to nil.
1 2 3 4 5 6 7 8 9 10 | - (void)myMethod { MyClass * myObject; myObject= [MyClass alloc]; // Do stuff [myObject release]; myObject = nil; } |
If you don’t want to release your objects manually you could make the use of an autorelease pool. If you send the autorelease message to an object it will be sent and added to the autorelease pool. At the end of an event loop, this autorelease pools is released by the application object and then all of the objects contained within it are released, too. At the beginning of the next loop, a new pool is created and so on.
Example 2
An autoreleased Object is considered to be valid whithin the scope where it received the autorelease message.
1 2 3 4 5 6 7 8 9 | - (void)myMethod { MyClass * myObject; myObject = [MyClass alloc]; [myObject autorelease]; // myObject will be valid until // the very end of this method! } |
Example 3
When you have a method that creates and returns an object autorelease is quite useful to make sure that an object will be released on time.
1 2 3 4 5 6 7 | - (NSString *)myFunction { NSString *myString = [[NSString alloc] initWithString:@"Hello String."]; [myString autorelease]; // we have to do this to prevent a memory leak return myString; } |
Example 4
There are so named convencience constructors which will return autoreleased objects. If you use them and you want to keep them at the end of a method block, you have to sent a retain message. So if you keept in mind to call release or autorelease for each alloc, you know have to complete the rule to : for each alloc and for each retain you have to call release or autorelease.
1 2 | // if we assume that myVar exists myVar = [[NSString stringWithCString:"Hello String."] retain]; |
So we can breakdown the memory management to some rules :
Rule 1 : Retention Count
- Within a given block, the use of -copy, -alloc and -retain should be equal the use of -release and -autorelease.
- Objects created using convenience cunstructors (e.g. NSString’s strintWithCString) are concidered autoreleased.
- Implement a -dealloc method to release the instance variables you own.
Example 1: alloc and release
1 2 3 4 5 6 7 8 | - (void)printHello { NSString *string; string = [[NSString alloc] initWithString:@"Hello"]; NSLog(string); // we created string with alloc -- release it [string release]; } |
Example 2: Convenience constructor
1 2 3 4 5 6 7 8 | - (void) printHello { NSString *string; string = [NSString stringWithFormat:@"Hello"]; NSLog(string); // we created string with convenience constructor // we can assume it's autoreleased } |
Rule 2 : Always use accessor methods
If you are using retain and release on a classes instance variables throughout your code, you are almost certainly doing the wrong thing. Use conistently accessor methods of classes to decrease memory management problems.
Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | @interface Counter : NSObject { NSNumber *count; } - (NSNumber *)count { return count; } - (void)setCount:(NSNumber *)newCount { [newCount retain]; [count release]; count = newCount; } - (void)dealloc { [self setCount:nil]; [super dealloc]; } - (void)reset { //*/ // YOU COULD DO : NSNumber *zero = [NSNumber numberWithInt:0]; [self setCount:zero]; /*/ // OR (if you have to alloc here) : NSNumber *zero = [[NSNumber alloc] initWithInt:0]; [self setCount:zero]; [zero release]; //*/ } |
Rule 2 : NSArray, NSDictionary, NSSet etc.
When you add an object to a collection class the collection retains it. A release message will be sent when the collection it self gets released. To understand this, think of what would you do if you are planning a collection class. You wanted to make sure that no objects you were given to look after disappeared out from under you else where, so you send them a -retain message as they’re passed in. If they’re removed, you have to send a balancing -release message. Same when your collection will be released, any remaining objects in your collection should be sent a -release message during your own -dealloc method.
The following examples are both correct.
Example 1
1 2 3 4 5 6 7 8 9 10 11 | -(void) myMethod { NSMutableArray *array; int i; // ... for (i = 0; i < 10; i++) { NSNumber *n = [NSNumber numberWithInt: i]; [array addObject: n]; } } |
Example 2
1 2 3 4 5 6 7 8 9 10 11 12 | -(void) myMethod { NSMutableArray *array; int i; // ... for (i = 0; i < 10; i++) { NSNumber *n = [[NSNumber alloc] initWithInt: i]; [array addObject: n]; [n release]; } } |
Release and dealloc
The release message will be sent by you or by an autorelease pool. The release method of an object decreases the reference counter by one, and if its zero calls the dealloc method.
Vicious retain circles
Guess we have an object A is retaining object B and object B is retaining object A. Now these objects never reach a zero retain count. Just in that moment the reference count gets to one, they are effectively out of the program. This is called vicious retain circles and it is possible to have very complex retain cirules like that where the minumum count is even higher than one. To avoid this you should always plan your class dependency wisely. Lets take a look on the Cocoa view hierachy. A NSView can have several subviews which have subviews and so on. On the other side a NSView has also a pointer to the superview. Why doesn’t this ends in an vicious retain circle? Well, NSViews retains their subviews but not their superview.
Further Links
- Documentation on developer.apple.com : Memory Managemet
About this entry
You’re currently reading “ iPhone Programming Part 2 : Objective C Memory Management ,” an entry on coders
- Author:
- hhamm
- Published:
- 2.12.09 / 1pm
- Category:
- objective c, programming, xcode
- Feedback:


9 Comments
Jump to comment form | comments rss [?] | trackback uri [?]