1. NSOperation 생명 주기 및 네트워크 전송 중 NSOperation 상태


가. autorelease pool 생성

NSOperation은 NSOperationQueue객체에서 실행되는 쓰레드 작업 단위의 객체입니다. 초기화 이후 Queue에 입력 된 이후 Queue에 의하 Start를 진행하게 됩니다.

Start단계에서는 객체에 필요한 사전 작업을 진행하고 (네트워크 상태체크, 여유 메모리 체크등) main을 실행하게 됩니다.

main단계는 실제 작업을 해야하는 것을 기술하게 되어있는데 메인쓰레드의 Autorelease Pool의 영역에서 벗어나기 때문에 자체 Autorelease Pool을 생성해야합니다.

만약 제대로 Pool을 생성안할 경우 Autorelease로 해제를 선언한 객체들은 릭을 유발하지 않지만 계속 메모리에 남게 되는 문제를 발생할 수도 있습니다.

 

참조 URL : http://stackoverflow.com/questions/184409/nsautoreleasepool-in-nsoperation-main


나. 비동기 방식 작업시 NSOperation 메모리 확보

일반적인 작업 단위로 NSOperation을 사용하게 될 경우 main이 종료되는 시점에서 객체가 해제됩니다.

하지만 네트워크 작업등 비동기 방식으로 NSOperation을 사용할 경우 주의 할 점이 있습니다.

비동기 방식으로 진행하기 때문에 main이 종료되어도 객체는 계속 살아있어야 합니다. (retainCount가 최소 1로 유지되어야함)

그 이유는 비동기 대상에서 응답을 델리게이트를 통해 처리해야하기 때문입니다.(만약 결과를 처리할 필요가 없으면 NSOperation객체가 살아 있을 필요는 없습니다.)

그럼 main이 종료된 이후에도 메모리에 유지시키기 위해서는 비동기 작업 대상에 자신을 델리게이트 객체로 등록을 해야하는데 보통 델리게이트 객체를 등록할 때는 Property의 assign 키워드를 통해 메모리를 참조만하고 있어야 하지만

위의 경우에는 Property의 retain키워드를 통해 retainCount를 확보해두어야 합니다. (그리고 비동기 객체가 종료 시점에 반드시 해제 시켜야 합니다. 그렇지 않을 경우 메모리릭이 발생 됨)


@interface NCTransOperation : NSOperation {

 NCTransPostManager * i_TransPostManager; // 비동기 대상 객체, 사용할 때 retainCount를 확보한다.
}

@interface NCTransPostManager : NSObject <HttpPostDelegate>{
- id i_Target; ///< 해당 클래스


}

@property (nonatomic, retain)id target;

//  NSOperation의 결과를 처리할 델리게이트 타겟, retain키워드를 사용하여 메모리를 확보한다.

 

- (void) dealloc
{
 self.target = nil; //< 델리게이트 타겟을 반듯이 해제시켜야 한다.

 [super dealloc];
}

 

 

2. NSOperation 취소하기

 

네트워크등으로 인해 NSOperation Queue의 제어를 벗어난 상황에서 취소하는 방법 (노티적용)

NSOperationQueue 내에서 NSOperation이 일방적인 방식으로 처리가 될 경우 isCancelled 및 cancel 메소드를 오버라이드를 통해 취소시 실행될 액션을 정의하면 됩니다.

(isCanceled는 객체의 취소상태를 판별하는 역활을 하며 cancel 메소드는 취소 진행시 실행 될 내용을 기술하면 됩니다.)

하지만 NSOperation이 비동기 방식으로 진행될 경우 비동기 진입 전까지는 (main 메소드내 진행상태) 위의 isCancelled와 cancel메소드가 작동하게 되지만 비동기의 응답을 기다리는 경우

NSOperationQueue의 제어권을 벗어난 상태이기 때문에 두 메소드가 제대로 실행이 안됩니다. 이 경우 제대로 취소 액션을 진행할 수 없어 예외상황을 발생시키는 경우가 발생합니다.

(취소를 발생시킨 객체는 이미지 종료되어 해제되었는데 NSOperation에서 객체에게 결과를 반환하려고 시도할때 Bad Access를 발생시킴)

그러므로 임의로 취소 단계를 돌입할 수 있는 방법을 구현을 해야합니다.

여러 방법이 있겠지만 가장 간편하게 구현할 수 있는 방법은 Notification을 사용한 Observing Pattern을 적용하는 것입니다. NSOperation이 실행될 때 취소 Notification을 등록하게 된면

NSOperationQueue의 제어를 벗어난 상태에서도 취소 단계에 돌입할수 있습니다. (NSOperationQueue의cancelAllOperations을 실행하기 전 Notificaion을 Posting하게 되면 비동기 상태에 있는 객체들도 반응하게되어

취소를 제대로 진행 할수 있게됩니다. 물론 NSOperation이 종료된 이후에는 Notification을 해제 시켜야합니다.

 


3. NSOperation의 Main thread 전환 시점

 

이미지 리사이즈 같은 이미지 프로세싱 작업은 작업단위가 크기 때문에 main Thread에서 처리하기에는 부담이 큽니다. 이때 사용자의 편의성을 유지시키기 위해 작업단위가 큰 작업은 쓰레드로 실행해야 합니다.

이때 쓰레드에서 작업한 결과(이미지 리사이즈 같은 결과물) 화면에 표시하기 위해서는 NSOperation을 main쓰레드로 변환을 시켜야 한다. 현재 작업을 main 쓰레드로 변환하기 위해서는 두 가지 방법이 있습니다.

 

가. NSOperation자체를 main쓰레드로 전환시킴

 

if ([NSThread isMainThread] == NO) {
 [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO];
 return;
}

 

나. NSOpreation 내 특정 메소드 실행을 main쓰레드로 전환시킴

 

[self performSelectorOnMainThread:@selector(complete:) withObject:outputImage waitUntilDone:NO];


'가' 와 같은 방법은 네트워크 전송등 특정 작업을 하기 위해 NSOperation을 main스레드로 전환시켜야 할 경우에만 사용해야 합니다. 하지만 위 처럼 이미지 변환 작업을 완료 후 결과를 main 쓰레드로 보내기 위해서는

'나'와 같은 방법을 사용하는 것이 좀더 효율적입니다. 만약 아래와 같이 NSOperation을 벗어 난 후 일반 객체에서 메인쓰레드로 전환시킬수도 있긴 하지만 이럴 경우 예외 상황들이 발생할 가능성이 많습니다.


객체1 (main Thread) -> NSOperation 실행 (Thread 2) -> NSOpeartion 종료 (Thread 2) -> 객체 1에 delegate를 통해 결과 반환 (Thread 2) -> 객체 1에서 메인쓰레드로 전환 후 결과를 사용함(performSelectorOnMainThread)


발생될 예외상황은 크게 두가지 인데 첫번째로는 메모리 경고 입니다.

여러가지 이유로 메모리 경고가 발생되는데 위와 같이 NSOperation을 벗어난 상태에서 쓰레드가 동작하면서 그 영향이 main 쓰레드까지 미치게 된다면 실제 가상메모리를 확보 할수 있음에도 불구하고 제대로 확보가 되지 않아

메모리 경고를 유발시키게 됩니다. 심할 경우 앱이 종료될 수도 있습니다. 특히 이미지 변환 같은 작업 단위가 클 경우 더욱 자주 발생됩니다.

두번째로는 비동기 처리와 같이호출 한 객체가 종료된 이후에 결과를 반환하려 할때 객체 검사게 제대로 이뤄지지 않아 Bad Access를 유발 시키게 됩니다. 이런 문제점을 해결하기 위해서는 꼭 쓰레드는 NSOperation 내에서 전환 되어야 합니다.

 

NSOperation은 objective C 프로그램에서 매우 유용한 Concurrency Program을 작성할 수있습니다. 하지만 예외 상황을 유발시키는 경우도 많기 때문에 많은 테스트를 해봐야 합니다.

'iOS' 카테고리의 다른 글

simbolicatecrash 위치  (0) 2011.10.06
SimpleURLConnections ios 5 문제 해결  (0) 2011.09.28
NSString 조합형, 완성형 문제  (0) 2011.08.31
SecItemCopyMatching 메모리릭  (0) 2011.08.17
Delegate를 사용시 주의할 점  (0) 2011.07.21

+ Recent posts