[출처: http://maclove.pe.kr/32]

메모리 관리

많은 개발자들이 Objective-C 의 메모리 관리를 어렵게 느낀다. Objective-C 에서 객체는 참조 카운터를 이용해서 관리되기 때문에, 참조 카운터를 증가 시키고 감소하는 작업이 프로그래머의 몫이 된다. 여기서 혼돈이 오는 것이다. 참조 카운터를 증가시키는 함수는 retain 이다. 반대로 참조 카운터를 감소시키는 함수는 release와 autorelease 이다. 하지만 문제는 이미 만들어진 객체의 메서드가 내부에서 retain 을 몇번 부르는지를 별도로 알아낼 방법이 없다는 것이다. 다음을 보자.

UIImageView* imgView = [[UIImageView alloc] init];

이 코드에서 UIImageView 는 retain 내부에서 한번 호출해서 객체를 반환해 준다. 그렇기 때문에 우리는 더이상 필요하지 않을때,

[imgView release];

를 호출해야 한다. 하지만 다음을 보자.

NSString* output = [NSString stringWithFormat:@”My name : %@”, name];

이 코드는 NSString의 stringWithFormat 클래스 메서드를 이용해서 객체를 생성하는 코드이다. 이 녀석은 retain 이 아닌 autorelease 를 호출해서 객체를 반환한다. 이렇게 어떤 메서드는 객체를 retain 해서 반환하고, 또 어떤 객체는 autorelease 로 반환하기 때문에 혼돈이 온다.

참조 카운트를 관리하는 함수는 다음과 같다.

• retain
     - 참조 카운트를 1 증가 시킨다.
• release
     - 참조 카운트를 1 감소시킨다. 참조 카운트가 0이 되면 메모리가 해제된다.
• autorelease
     -  객체를 오토릴리즈 풀에 등록한다. 나중에 오토릴리즈 풀이 제거될때 release 를 호출해 준다.

객체의 참조를 관리하는 것은 위 3개의 메서드가 전부이지만, 문제는 클래스 내부 구현에서 위 함수들을 호출하는 지를 모른다는 점이다. 하지만 법칙이 있다. 애플이 작성한 모든 클래스는 정해진 규칙을 철저하게 따르기 때문에 이 법칙들만 알아두면 더 이상 햇갈릴 일이 없다.

* 규칙1 : alloc, copy, new를 이름에 포함하는 메서드는 retain 된 객체를 반환한다.

alloc, copy, new 가 메서드 이름에 포함되어 있다면, 그 때 반환되는 객체는 retain 되어 있다. 그래서 반드시 release 를 직접 호출해야 한다.

01: queue = [[NSOperationQueue alloc] init];
02: // 작업
03: [queue release];
04:
05: copyedObj = [name copy];
06: // 작업
07: [copyedObj release];

* 규칙2 : 결자해지

만약 자신이 retain 을 호출했다면, 책임지고 release 또는 autorelease 를 호출해 주자.

01: [objA retain];
02: // 작업
03: [objA release];

반드시 자신이 호출한 retain 에 대해서 release/autorelease 짝을 맞추도록 하자.

* 규칙3: 클래스 메서드가 객체를 생성해 줄때는 autorelease 객체를 반환한다.

클래스 메서드로 객체를 생성하는 경우 즉 stringWithFormat 과 같은 클래스 메서드가 반환하는 객체는 모두 autorelease 객체이다.

01: img = [UIImage imageNamed:@"test.png"];
02: imgView = [[UIImageView alloc] initWithImage:];
03: // 작업
04: [imgView release];

코드 1행의 imageNamed 메서드 처럼 클래스 메서드를 이용해서 객체를 생성하는 경우 그 객체는 autorelease 가 호출된 객체이다. 그렇기 때문에 별도로 release 를 호출하지 않아도 오토릴리즈 풀이 자동으로 release 를 호출해 준다. 하지만 이 객체에 retain 을 호출 했다면 호출한 만큼의 release 를 호출 해야한다.

* 규칙4: 포함 객체는 추가된 객체를 retain 하고, 항목을 제거할 때 release 한다.

NSArray,NSDictionay 등의 포함 객체는 항목으로 추가되는 객체에 대해서 retain 을 한번 호출한다. 그리고 객체가 포함객체에서 제거될때 release 를 호출해 준다.

13.9.5 규칙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 를 호출한 이유를 이해할 것이다.

*규칙5: 메서드가 반환하는 객체는 autorelease

메서드가 객체를 반환한다면 autorelease 된 객체를 반환하는 것이 좋다.

01: -(NSString*) findTopPlayer {
02: NSString *ret = [[top objectAtIndex:0] copy];
03: [ret autorelease];
04: return ret;
05: }

[출처: http://maclove.pe.kr/32]



출처 : http://blog.naver.com/PostView.nhn?blogId=baek2187&logNo=150059860682
Posted by 오늘마감

댓글을 달아 주세요