Autorelease Pool
- When you want to start doing more programming using NSString and other Foundation framework classes you need a more flexible system. This system is using Autorelease pools.
- When developing Mac Cocoa applications, the auto release pool is setup automatically for you.

main.m
#import <Foundation/NSString.h>
#import <Foundation/NSAutoreleasePool.h>
#import <stdio.h>

int main( int argc, const char *argv[] ) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSString *str1 = @"constant string";
    NSString *str2 = [NSString stringWithString: @"string managed by the pool"];
    NSString *str3 = [[NSString alloc] initWithString: @"self managed string"];

    // print the strings
    printf( "%s retain count: %x\n", [str1 cString], [str1 retainCount] );
    printf( "%s retain count: %x\n", [str2 cString], [str2 retainCount] );
    printf( "%s retain count: %x\n", [str3 cString], [str3 retainCount] );

    // free memory
    [str3 release]; // alloc으로 생성한 것만 release. 나머지는 AutoreleasePool에서 처리

    // free pool
    [pool release];
   
    system("PAUSE");
    return 0;
}


결과
constant string retain count: 40387657
string managed by the pool retain count: 1
self managed string retain count: 1
계속하려면 아무 키나 누르십시오 . . .

- If you run this you'll notice a few things. One is that the retainCount of str1 is ffffffff.
  라는데 내 예제에선 이상한 숫자만... ㅡ.ㅡ;;
- The other is, I only release str3, yet this program is memory management perfect. The reason is the first constant string is added to the autorelease pool automatically. The other string is made using stringWithString. This method creates a string that is owned by NSString class, which also puts it in the auto release pool.
  str3 하나만 release 했지만 이 프로그램의 메모리 관리는 완벽하다는 군. str1, str2 생성 시의 방법이 string을 알아서 auto release pool에 넣는다는.
- It's important to remember, for proper memory management, that convience methods like [NSString stringWithString: @"String"] use autorelease pools, but alloc methods like [[NSString alloc] initWithString: @"String"] do not use autorelease pools for managing memory.
  stringWithString 같이 auto release pool을 사용하는 메소드를 쓰는 것이 편하다.
- There are two ways to manage memory in Objective-C: 1) retain and release or 2) retain and release/autorelease.
   For each retain, there must be one release OR one autorelease.


Auto Release Pool 사용 예제

Fraction.h
#import <Foundation/NSObject.h>

@interface Fraction: NSObject {
    int numerator;
    int denominator;
}

-(Fraction*) initWithNumerator: (int) n andDenominator: (int) d;
-(Fraction*) initWithNumerator: (int) n denominator: (int) d;
+(Fraction*) fractionWithNumerator: (int) n denominator: (int) d;
-(void) print;
-(void) setNumerator: (int) n;
-(void) setNumerator: (int) n andDenominator: (int) d;
-(void) setDenominator: (int) d;
-(int) numerator;
-(int) denominator;
@end


Fraction.m
#import "Fraction.h"
#import <stdio.h>

@implementation Fraction
-(Fraction*) initWithNumerator: (int) n andDenominator: (int) d {
    self = [super init];
   
    if(self) {
        [self setNumerator: n andDenominator: d];
    }
   
    return self;
}

-(Fraction*) initWithNumerator: (int) n denominator: (int) d {
    self = [super init];
   
    if(self) {
        [self setNumerator: n andDenominator: d];
    }
   
    return self;
}

// Auto Release Pool
+(Fraction*) fractionWithNumerator: (int) n denominator: (int) d {
    printf( "Create object using auto release pool.\n");
   
    Fraction *ret = [[Fraction alloc] initWithNumerator: n denominator: d];
    [ret autorelease]; // retain count -1: 이후 auto release pool을 release 할 경우 자동 처리됨.

    return ret;
}

-(void) print {
    printf( "%i/%i", numerator, denominator );
}

-(void) setNumerator: (int) n {
    numerator = n;
}

-(void) setNumerator: (int) n andDenominator: (int) d {
    numerator = n;
    denominator = d;
}

-(void) setDenominator: (int) d {
    denominator = d;
}

-(int) denominator {
    return denominator;
}

-(int) numerator {
    return numerator;
}

// dealloc
-(void) dealloc {
    printf( "Deallocing fraction : %i\n", numerator );
}
@end


main.m
#import <Foundation/NSAutoreleasePool.h>
#import "Fraction.h"
#import <stdio.h>

int main( int argc, const char *argv[] ) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    Fraction *frac1 = [Fraction fractionWithNumerator: 2 denominator: 5];
    Fraction *frac2 = [Fraction fractionWithNumerator: 1 denominator: 3];

    // print frac 1
    printf( "Fraction 1: " );
    [frac1 print];
    printf( "\n" );

    // print frac 2
    printf( "Fraction 2: " );
    [frac2 print];
    printf( "\n" );

    // this causes a segmentation fault
    //[frac1 release];

    // release the pool and all objects in it
    printf( "Auto Release Pool release.\n" );
    [pool release]; // 이 안에 담긴 object들이 모두 release 되면서 dealloc 됨.
   
    system("PAUSE");
    return 0;
}


결과
Create object using auto release pool.
Create object using auto release pool.
Fraction 1: 2/5
Fraction 2: 1/3
Auto Release Pool release.
Deallocing fraction : 2
Deallocing fraction : 1
계속하려면 아무 키나 누르십시오 . . .

- In this example, the method is a class level method. After the object is created, autorelease is called on it. Inside the body of the main method, I never call release on the object.
- The reason this works is because: for every retain, one release or autorelease must be called. The object's retain count starts out as 1, and I called autorelease on it once. This means 1 - 1 = 0. Once the autorelease pool is released, it counts the autorelease calls on all objects and decrements them with [obj release] with the same number of times autorelease was called per object.
- As the comment says, uncommenting that line causes a segment fault. Since autorelease was already called on the object, calling release on it, and then releasing the autorelease pool would attempt to call dealloc on an object that is nil, which is not valid. The end math is 1 (creation) - 1 (release) - 1 (autorelease) = -1.
  autorelease 하면 -1 되므로 생성 후 다시 release 하면 segmentation fault.
- Auto release pools can be dynamically created for large amounts of temporary objects. All one must do is create a pool, perform any large chunk of code that creates lots of temporary objects, then release the pool. As you may wonder, it this means it is possible to have more than one auto release pool at a time.
 Auto release pool도 동적으로 생성할 수 있다 -> 여러 개의 풀을 생성할 수 있다.

'프로그래밍 > iPhone Dev' 카테고리의 다른 글

[Objective C] 15 NSDictionary  (0) 2009.11.13
[Objective C] 14 NSArray  (0) 2009.11.13
[Objective C] 12 Dealloc  (1) 2009.11.12
[Objective C] 11 Retain and Release  (0) 2009.11.12
[Objective C] 10 Protocols  (0) 2009.11.11