메서드를 함수로 호출
사실, Objective-C 메서드는 실제로 C언어의 함수와 동일합니다. 평소에는 은폐되어 있고, 첫 번째 인수에 자신의 클래스를 참조하는 객체를 가지는 함수입니다.
메서드의 실체가 함수라는 사실은 C언어와 호환성이 매우 높다는 것을 의미합니다. 순수한 C언어로 작성된 라이브러리에서 Objective-C의 메서드를 호출하거나, 객체를 이용하는 것도 크게 문제가 없습니다.
Objective-C 메서드는 항상 IMP 형식으로 정의됩니다. IMP 형식은 헤더 파일에 다음과 같이 정의되어 있습니다.
typedef id (* IMP) (id, SEL, ...);
이 정의에서 알 수 있듯이, Objective-C에 선언된 모든 메서드는 암시적으로 id 형식 SEL 형식의 인수를 가집니다. 첫 번째 인수는 메서드를 호출하는 객체를 나타내는 변수 self입니다. 두번째 인수는 이 메서드의 셀렉터를 나타내는 변수 _cmd입니다. 모든 메서드는 이러한 숨겨진 인수가 반드시 존재합니다. 그런 다음 메서드 선언에 따라 인수가 결정되는 것입니다.
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 형식은 메서드의 포인터를 사용하여 직접 메서드를 호출합니다.