standwally

autorelease 본문

프로그래밍/iOS

autorelease

standwally 2013. 2. 22. 01:10

오브젝트에 release 메시지를 보내면, 리테인 카운트가 하나 감소합니다.

autorelease는 리테인 카운터의 디크리먼트를 지연시킵니다.

지연시킨다는 것은 무슨 뜻일까요?

오브젝트에 autorelease 메시지가 던져지면, 자동 해제 풀(NSAutoreleasePool)에 등록됩니다.

NSAutoreleasePool 오브젝트는 자신이 파괴될 때, 등록된 모든 오브젝트에 대해 release를 보내도록 설계되어 있습니다.

이런 시스템 때문에, autorelease는 오브젝트 자신의 레퍼런스 카운트를 하나 감소시키는 것이 아니라, NSAutoreleasePool 오브젝트가 파기될 때까지 지연시킵니다.

그렇다면 대체 어느 타이밍에서 NSAutoreleasePool 오브젝트가 생성되고, 파기되었을까요?

이 타이밍을 생각해 보기 위해서는, 애플리케이션이 동작하는 구조를 알아야 할 필요가 있습니다.

iPhone 어플리케이션은 이벤트가 발생하는 것을 기다리다가, 이벤트가 발생하면 각각의 이벤트에 해당하는 처리로 분기하고, 대응한 후 다시 이벤트가 발생하기를 기다리는 것을 계속해서 반복하는 것입니다.

이와 같은 어플리케이션을 일반적으로 이벤트 구동형 어플리케이션이라고 합니다. 여기서, 만약 이벤트가 발생해서 처리할 때마다 NSAutoreleasePool 오브젝트를 만들고, 그 처리를 마쳤을 때 파기한다면 어떻게 될까요?

이벤트에 대응하는 처리 중에 autorelease가 던져진 오브젝트는 이벤트 대응 처리가 종료될 때 NSAutoreleasePool 오브젝트가 파기되므로, 그 때 release 메시지가 보내지게 됩니다. 그러므로 위에서 제기했던 주목해 볼 타이밍은 이벤트와 이벤트 사이입니다. 이 이벤트 사이가 바로 NSAutoreleasePool에 등록된 오브젝트에 release 메시지를 던질 수 있는 타이밍입니다.

실제 Xcode를 이용하여 샘플 프로젝트를 만들고, NSAutoreleasePool이 해제되는 시점을 확인해 보겠습니다.

먼저 이벤트를 발생시켜서 오브젝트 하나에 autorelease 메시지를 보내어 NSAutoreleasePool에 등록하는 시점에 브레이크 포인트를 설정하고 스레드 리스트를 캡쳐해 보았습니다.

스레드 리스트에서 NSFireDelayedPerform이라는 이름안에 보면 NSPushAutoreleasePool/NSPopAutoreleasePool 이 두가지 단어를 확인할 수 있습니다. 그리고 좀더 자세지 보면 아래 그림과 같이 NSPopAutoreleasePool에 이르기 전에 이벤트가 발생했다는 것도 확인할 수 있습니다.

그 다음에는, autorelease 메시지를 보낸 오브젝트에 dealloc 메서드를 오버라이드 하여, dealloc 메서드 안에 브레이크 포인트를 설정하고 스레드 리스트를 캡쳐해보았습니다.

호출 스택 리스트에 보면 CFAutoreleasePoolPop이라는 이름이 있습니다. 이것이 최상위 NSAutoreleasePool을 파기하는 작업입니다. 그리고 그 밑에 이름은 NSPushAutoreleasePool/NSPopAutoreleasePool을 갖고 있있던 NSFireDelayedPerform입니다.

여기까지 오브젝트에 autorelease 메시지를 보내어 리테인 카운트의 디크리먼트를 지연시킨다는 의미를 확인하기 위해서, NSAutoreleasePool이 해제되어 NSAutoreleasePool에 등록된 오브젝트에게 release 메세지를 보내는 타이밍에 대하여 확인해 보았습니다.