메소드를 함수로서 호출한다

실은, Objective-C 의 메소드의 실태는 C 언어의 함수와 같습니다. 평상시는 은폐 되고 있습니다만, 메소드와는 최초의 인수에 자신의 클래스를 참조하는 오브젝트를 받는 함수입니다.

메소드의 실체가 함수이다고 하는 사실은 C 언어와의 친화성이 지극히 높은 것을 의미하고 있습니다. 순수 C 언어로 기술된 라이브러리로부터 Objective-C 의 메소드를 호출하거나 오브젝트를 이용하는 것도 무리한 이야기는 아닙니다.

Objective-C 의 메소드는, 항상 IMP 형태로 정의됩니다. IMP 형태는, 헤더 파일로 다음과 같이 정의되고 있습니다.

typedef id (*IMP)(id, SEL, ...);

이 정의로부터도 알 수 있듯이, Objective-C에 선언된 모든 메소드는, 암묵적으로 id 형태와 SEL 형태의 인수를 가집니다. 제일 인수는, 메소드를 호출한 오브젝트를 나타내는 변수 self 입니다. 제2 인수는, 이 메소드의 실렉터를 나타내는 변수 _cmd 입니다. 모든 메소드에는, 이러한 숨겨진 인수가 반드시 존재합니다. 그 다음은, 메소드의 선언에 따라 인수가 결정되겠지요.

C 언어나, 어떠한 이유로 Objectiver-C로부터, 메소드를 함수로서 호출할 필요가 있는 경우, 메소드를 참조하는 함수에의 포인터를 취득하면 좋습니다. 메소드를 참조하는 IMP 형태의 포인터는 Object 클래스의 instanceMethodFor 클래스 메소드, 또는 methodFor 인스턴스 메소드로부터 얻을 수 있습니다.

+ (IMP)instanceMethodFor:(SEL)aSel;

- (IMP)methodFor:(SEL)aSel;

aSel 에는 대상 메소드의 IMP, 즉 함수에의 포인터를 취득하고 싶은 실렉터를 지정합니다. 메소드는 aSel로 지정된 실렉터가 특정하는 메소드의 포인터를 돌려줍니다.

포인터를 취득할 수 있으면, C 언어로부터에서도 인스턴스 메소드를 호출할 수 있게 됩니다. 함수의 포인터로서 직접 호출하기 위해, 메세지 통신보다 고속으로 되는 점도 특징이지요.

#import <stdio.h>
#import <objc/Object.h>

@interface Test : Object
- (void)Write;
@end

@implementation Test
- (void)Write {
	printf("I am the bone of my sword.\n");
}
@end

int main() {
	id obj;
	SEL method;
	IMP func;

	obj = [Test new];
	method = @selector(Write);
	func = [Test instanceMethodFor:method];
	func(obj , method);

	return 0;
}

이 프로그램은 Test 클래스의 인스턴스 메소드 Write 에의 포인터를 취득해, IMP 형태의 변수 func 에 보존하고 있습니다. [Test instanceMethodFor:method] 과 같은 메세지 부분은, [obj methodFor:method] 이라고 해도 의미는 같습니다. 이 메세지식이 돌려주는 IMP 형태의 메소드의 포인터를 사용하고, 직접 메소드를 호출하고 있습니다.

화상 처리나 멀티미디어 등, 루프 처리의 고속화등이 필요한 경우, 메세지 통신이나 실렉터 통신은 부담이 커집니다. 속도를 고집하는 프로그램이면, 필요에 따라서 IMP 를 취득해, 포인터로부터 메소드를 호출해도 좋을 것입니다.

Posted by tklee