objective c memory management

Tue, Apr 20, 2010

A simple digest of the Cocoa Memory Management Rules.

Using alloc/new/copy means the object you’ve just created has a retainCount of 1 and you must release it, either as soon as you’re finished with it:

Cake *cake = [[Cake alloc] init];
[cake eat];
[cake release];or in your dealloc method:
Cake *cake;

  • (void)getCake { cake = [[Cake alloc] init]; }

  • (void)eatCake { [cake eat]; }

  • (void)dealloc { [cake release]; }

If you get hold of the object any other way, you don’t have to bother managing it as you can assume it has a retainCount of 1 and is autoreleased, unless you want it to hang around for a while, in which case you have to retain it:
CakeTrolley *cakeTrolley;
Cake *cake;
Cake *largeCake;

  • (void)getCakeTrolley { cakeTrolley = [[CakeTrolley alloc] init]; }

  • (void)addCakeToTrolley { cake = [cakeTrolley addCake]; [cake eat]; // cake goes away by itself }

  • (void)addLargeCakeToTrolley { largeCake = [cakeTrolley addLargeCake]; // It’ll take some time to eat this one so hang on to it. // If we don’t retain it here, it may be autoreleased at // the end of the event loop… [largeCake retain]; [largeCake eatSome]; }

  • (void)feelingHungry { [largeCake eatSome]; }

  • (void)dealloc { [largeCake release]; [cakeTrolley release]; }

  • What about returning objects from a method? In the old days it was known as “returning the address of a local variable” and was a hangable offence! In Objective-C, just use autorelease:
    // CakeTrolley class

  • (Cake *)addCake { Cake *cake = [[CakeTrolleyCake alloc] init]; return [cake autorelease]; }

  • (Cake *)addLargeCake { Cake *largeCake = [[CakeTrolleyCake alloc] initWithSize:HUGE]; return [largeCake autorelease]; }

  • What if you’re really greedy and want to eat thousands of cakes in one go? All those autoreleased cake objects are going to mount up, which could impact on performance, especially if you’re running on the iPhone. Well, you can add a new autorelease pool to the stack and use it to mop up afterwards, or during your cake bender:
    CakeTrolley *cakeTrolley;
    Butler *butler;

  • (void)getCakeTrolley { cakeTrolley = [[CakeTrolley alloc] init]; }

  • -(void)geButler { butler = [[Butler alloc] initWithCakeTrolley:cakeTrolley]; }

    • (void)eatTonsOfCakes { [butler feedMeTonsOfCakes]; }

    • (void)dealloc { [butler release]; [cakeTrolley release]; }

    // Class Butler

    • (void)feedMeTonsOfCakes { Cake *cake; int cakeCount; NSAutoreleasePool *cakePool = [[NSAutoreleasePool alloc] init];

    // Let’s eat a MILLION cakes, yum! for (cakeCount=0; cakeCount < 1000000; cakeCoount++) { // Each Cake object is autoreleased by CakeTrolley so our local pool catches it cake = [cakeTrolley addCake]; [cake eat]; }

    [cakePool release]; }

    You can also release and recreate the pool on every iteration to really keep the memory footprint under control as it’s very cheap to do so.


    comments powered by Disqus