다중인자를 갖는 PerformSelector 메시지

Objective-C 2011. 3. 23. 15:31




이번 포스팅에서는 다중 파라미터를 갖는 Selector를 인자로 받아  별도의 쓰레드에서 처리를 해주는 비동기 메서드
구현에 대해서 알아볼 것이다.

아이폰 앱 프로젝트 진행 중 Delegate 패턴을 구현하면서  PerformSelector 류의 메서드를 사용 할 필요가 생겼다.
Cocoa Touch 프레임웍에서는 최대 2개까지의 인자를 받는 메서드(performSelector:withObject:withObject:) 만을 제공하고,
더 많은 파라미터를 전달해야 할 경우, 클래스 또는 Dictionary를 사용하여 전달해야 했다.  매번마다 파라미터를  담기위해 Dictionary를 생성하고, 데이터를 꺼내쓰는 것은 상당히 번거로운 작업이었다.
외국 블로그에서 우연히 이 문제를 깔끔하게 해결해주는 코드를 발견했다.  C언어의 가변인자 리스트와 Objective-C 의 
NSInvocation 메커니즘을 사용하는 방법이었다.  이 포스팅에서는 가변인자 리스트와 NSInvocation 메커니즘에 대해서는
설명하지 않겠다. 추후 Objective-C 런타임 메커니즘을 알아보면서 NSInvocation에 대해서 자세히 알아볼 것이다.


다음은 가변인자 리스트와 NSInvocation을 사용하여 다중 파라미터를 갖는 Selector를 호출하는 예제코드이다. 

- (void)performSelector:(SEL)aSelector withContext:(void*)context,... {
	if (context) {
		NSMethodSignature *signature = [self methodSignatureForSelector:aSelector];
		NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
		[invocation retainArguments];
		
		NSUInteger argumentCount = [signature numberOfArguments] - 2;
		
		[invocation setTarget:self];			// index 0
		[invocation setSelector:aSelector];	    // index 1
		
		va_list arguments;
		
		va_start(arguments, context);
		
		// 인자의 개수는 +2가 된 상태 
		NSUInteger i, count = argumentCount;
		void *currentValue = context;
		
		for (i = 0; i < count; i++) {
			[invocation setArgument:¤tValue atIndex:(i + 2)];
			currentValue = va_arg(arguments, void*); // 다음 인자 읽기 
		}
		
		va_end(arguments);
		
		NSThread *customWorkerThread = [NSThread currentThread];
		
		[invocation performSelector:@selector(invoke) onThread:customWorkerThread withObject:nil waitUntilDone:NO];
		
	} else {
		[self performSelectorInBackground:aSelector withObject:nil];
        
	}
}


위 메서드를 사용하여 아래와 같이 세 개의 인자를 갖는  printArgument:andOther:andAnother: 메시지를 호출하면...

// 호출할 메서드 
- (void)printArgument:(NSString*)arg1 andOther:(NSString*)arg2 andAnother:(NSString*)arg3 {
	NSLog(@"%@", [NSThread currentThread]);  
	NSLog(@"arg1: %@", arg1);
	NSLog(@"arg2: %@", arg2);
	NSLog(@"arg3: %@", arg3);
}

// 요렇게 호출할 수 있다. 깔끔하지 않는가? 
[self performSelector:@selector(printArgument:andOther:andAnother:) withContext:@"t1", @"t2", @"t3", nil];

위 메소드를 카테고리로 정의해놓으면 아주 유용하게 사용할 수 있을 것이다.

[소스 출처]


'Objective-C' 카테고리의 다른 글

Objective-C 문자열 조작 메서드  (0) 2011.04.29
다중인자를 갖는 PerformSelector 메시지  (0) 2011.03.23
Protocol 과 Category  (0) 2011.03.22
Objective-C 훑어보기  (2) 2011.03.20
[Cocoa] Cocoa Design Pattern  (0) 2011.03.20
HMAC-SHA1 구현  (0) 2011.03.03