맥부기 애플(iOS,Mac) 개발자모임 :: 네이버 카페:
autoelease
Reference counting
Reference count는 객체(Object)에 대한 소유권을 요구하는 수를 기록한다.
만약 직접 생성하지 않은 객체를 사용할 경우 retain 한다. > Reference count 1 증가
생성되거나 retain 객체를 다 사용했을 때는 삭제해야 한다. > Reference count 1 감소
"객체의 Reference count가 0이 되었을 때, 마지막으로 메모리에서 객체가 해제된다. "
Reference count에 영향을 주는 메소드들
alloc: 해당 객체에 메모리를 할당하고 Reference count를 1 증가 시킴
retain: 해당 객체의 Reference count를 1 증가 시킴
copy: 해당 객체의 복사본을 만듬. 그리고 복사본의 Reference count를 1 증가 시킴
release: 해당 객체이 Reference count를 1 감소 시킴
autorelease: 정해 지지 않은 시점에 해당 객체의 Reference count를 1 감소시킴
• alloc...으로 시작하는 메소드: 메소드를 호출한 쪽이 인스턴스의 오너가 된다.
• copy...으로 시작하는 메소드: 메소드를 호출한 쪽이 복제된 메소드의 오너가 된다.
• retain...으로 시작하는 메소드: 메소드를 호출한 쪽이 Receiver 인스턴스의 오너가 된다.
"* 규칙1 : alloc, copy, new를 이름에 포함하는 메서드는 retain 된 객체를 반환한다."
release 를 직접 호출해야 한다.
* 규칙2 : 결자해지
"retain 을 호출했다면, 책임지고 release 또는 autorelease 를 호출해 주자. "
* 규칙3: 클래스 메서드가 객체를 생성해 줄때는 autorelease 객체를 반환한다.
[ClassName Method:Para];
"* 규칙4: 포함(NSArray,NSDictionay,...) 객체는 추가된 객체를 retain 하고, 항목을 제거할 때 release 한다."
* 규칙5: retain 속성을 갖는 접근자
프로퍼티를 구성할때 @property (retain) ... 과 같이 retain 속성을 지정하면
이 프로퍼티에 객체를 설정하면 retain 메서드를 호출한다.
01: myImage = [[UIImage alloc] init]; // myImage 에 retain –> 1
02: self.userImage = myImage; // myImage 에 retain –> 2
03: [myImage release]; // myImage 에 release –> 1
04: // ...
05: self.userImage = myImage2; // 예전 myImage 에 release -> 0 해제
이와 같이 객체를 설정하는 접근자는 일반적으로 그 객체에 대해서 retain 을 호출한다.
그리고 만약 다른 객체를 재설정하면, 예전 객체에 release 를 호출한다.
위 예제의 3행에서 release 를 호출한 이유를 이해할 것이다.
*규칙6: 메서드가 반환하는 객체는 autorelease
메서드가 객체를 반환한다면 autorelease 된 객체를 반환하는 것이 좋다.
주의해야 할점
객체를 직접 생성하지 않았을 경우(메소드로부터 가져 왔을 경우 등...)
오직 인스턴스 변수나 정적 변수에 저장할 때 Retain 한다.
오직 명시적으로 할 경우나 위 경우처럼 retain되었을 경우 Release 한다.
"객체를 직접 생성했을 경우([[SomeClass alloc] init]나 [myInstance copy]로 생성했을 경우, 단 autoreleasing 없이..)"
명시적으로 Retain 할 필요 없음
사용이 완료되었을 때 Release 한다.
모든 retain과 release는 일치해야 한다.: init과 copy는 암묵적인 reatin을 한다.
"만약 언제 retain을 해야 할지 않 할지 모를 경우 하지마라, retaing 초과보다 releasing 초과가 디버깅하기 더 쉽다."
총정리: 메모리 릭 방지를 위한 규칙
"1. 블럭 내에서는 alloc, retain, copy의 수와 release, autorelease의 수가 동일해야 한다."
2. factory 함수를 사용해 생성한 객체의 경우 대부분 autorelease로 반횐된다. 따라서 release할 필요가 없다.
3. 클래스의 인스턴스 변수들은 dealloc 메소드에서 다 release해야 한다.
일정 구간을 또 다른 NSAutoreleasePool로 묶는다
// 1차 autorelease pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for(int i = 0; i < 100000; i++){
// pool이 담당하는 autorelease 구간
// autorelease #1
" [NSString stringWithFormat:@""autorelease test""];"
}
sleep(5);
// 2차 autorelease pool
NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init]; for(int i = 0; i < 100000; i++){
// pool2가 담당하는 autorelease 구간
// autorelease #2
" [NSString stringWithFormat:@""autorelease test""];"
}
// autorelease #2 영역의 데이터 정리
[pool2 release];
sleep(5);
[pool release];
"메모리 할당은 alloc, copy, retain method"
parameter값으로 넘겨받은 값은 해당 procedure내에서는 그 값이 그대로 유지된다.
해당 procedure에서 값을 넘겨받고 버릴것이라면 retain할 필요가 없다.
그렇지만 같은 class내 다른 procedure에서도 그 값을 필요로 하는 경우라면 retain이나 copy를 해둬야 한다.
객체를 복사하기.
이미 생성되어 있는 객체의 복사본을 얻는 방법이 있다.
복사라는 말은 객체를 하나 더 만들되 그 객체의 내용을 원본객체의 내용과 똑같게 하는 것이다.
anotherObject = [anObject copy];
anObject는 이미 존재하는 객체라고 가정하고 위의 코드는 anObject와 내용이 똑같은 새로운 객체를 생성해서 anotherObject변수에 대입한다.
"객체복사가 끝난 직후에는 anObject와 anotherObject가 내용이 똑같겠지만,"
결국 실제는 다른 객체이기 때문에 복사후 anObject에 변경을 가하더라도 anotherObject에 영향을 미치지는 않는다.
그러니 없던 객체를 생성한 꼴이된다.
"복사된 객체는 원본객체와 같은 클래스이고, 원본객체가 가지고 있던 모든 인스턴스변수에 대입되어 있던 객체나 값들도 새로운 객체에 복사된다."
"객체를 복사하는 것에서 한가지 알아야 하는 점은 -copy라는 객체 복사 메소드에 의해 리턴되는 새로운 객체는 retainCount가 1이며, autorelease되어지지 않는다."
"즉 +new를 이용해서 생성한 것과 같다. 그러므로, 복사해서 사용한 객체도 사용이 끝나면 반드시 release해 주어야 한다는 점을 잊지 말자."
NEXTSTEP style anObject = [NSObject new];
OpenStep style anObject = [[NSObject alloc] init];
댓글 없음:
댓글 쓰기