클래스 형식
Objective-C에서 생성된 클래스의 인스턴스는 id 변수에 저장할 수 있습니다. id 형식은 void *와 아주 유사한 형태로, 형태에 상관없이 인스턴스를 저장할 수 있는 일반적인 객체의 형식입니다. 따라서 id 변수의 실체는 컴파일 타임이 아닌 런타임에 결정된다는 동적인 특징이 있습니다.
그러나 런타임에 인스턴스를 확인하는 것은, 예를 들어 메서드를 호출하기 위해 객체에 메시지를 보낼 때 해당 메시지에 대응하는 메소드가 존재하지 않을 가능성이 있습니다. 다음과 같은 프로그램은 그러한 예제 중의 하나입니다.
#import <stdio.h>
#import <objc/Object.h>
@interface A : Object
- (void) Write;
@end
@implementation A
- (void) Write
{
printf ( "I am the born of my sword. \n");
}
@end
int main()
{
id obj1 = [A new];
id obj2 = [Object new];
[obj1 Write];
[obj2 Write]; // 런타임 오류
return 0;
}
이 프로그램은 A 클래스의 인스턴스를 생성하고 Write 메시지를 보낼 수 있습니다. 마찬가지로 Object 클래스의 인스턴스를 생성하고 Write 메시지를 보낼 수도 있습니다. Object 클래스는 Write 메서드가 존재하지 않지만, 정상적으로 컴파일 할 수 있습니다. 이것은 Objective-C 메시지 호출이 런타임에 결정된다는 특징을 나타냅니다.
컴파일된 프로그램을 실행하면 obj1 변수에 Write 메시지를 보내는 것은 성공하지만, obj2 변수는 Object 클래스의 객체이므로 Write 메소드가 존재하지 않기 때문에 obj2 변수에 Write 메시지를 보낼 때 런타임 오류가 발생합니다.
따라서 id 형식은 일반적인 객체 단위로 클래스의 인스턴스 데이터를 다룰 때는 유용하지만, 특정 클래스를 가정해서 사용하는 경우에는 적합하지 않습니다. 특히 큰 프로그램에서, 많은 인스턴스를 생성하는 경우, id 형식을 대량으로 사용하면 어떤 변수에 어떤 클래스 형식의 객체를 저장하고 있는지를 알 수 없게 됩니다 .
형식 판정을 런타임이 아닌 컴파일 타임에 할 수 있으면 컴파일러에서 형식을 확인하는 용도로 사용할 수 있습니다. 형식이 컴파일 타임에 확인되면 메시지 방식을 이용하여 대상 클래스 형식에 지정된 메서드가 존재하는지 여부를 확인하고 필요에 따라 경고도 발생시킬 수 있습니다. 컴파일 타임에 정적으로 클래스 형식을 결정하기 위해서는, id 형식이 아닌 클래스 이름을 형식과 클래스 형의 포인터로 사용하여 인스턴스를 참조합니다. 예를 들어, Point 클래스 전용 변수는 Point 형식의 포인터로 선언합니다.
#import <stdio.h>
#import <objc/Object.h>
@interface A : Object
- (void) Write;
@end
@implementation A
- (void) Write
{
printf ( "A. Write Method \n");
}
@end
int main()
{
A * obja = [A new];
[obja Write];
[obja free];
return 0;
}
이 프로그램은 A 클래스의 인스턴스를 만들고 A * 변수인 obja에 저장합니다. 지금까지는 id 형식의 객체에 저장했습니다만, 이 프로그램은 명시적으로 클래스 A의 형식임을 지정하였습니다.
클래스 형식의 포인터는 메모리에 객체 인스턴스의 주소를 저장하는 데 사용됩니다. id 타입도 인스턴스의 주소를 저장 하기 위한 것이지만, 클래스 형식을 지정하는 것이 명확합니다. 일반적으로 Objective-C의 클래스 형식 변수는 구조체에서와 같이 정적 변수로 선언할 수 없습니다. 클래스 형식의 변수는 항상 포인터 타입으로 선언 되어야 합니다.
SmallTalk를 근본으로 하는 Objective-C에서는 비교적 id 형식이 자주 사용되는 경향이 있지만, 현대의 여타 객체 지향 언어에 비추어 볼때, 클래스 타입을 명시한 변수를 사용하는 것이 좋습니다. id형식을 사용하는 것은 alloc과 init 같은 반환 값이 다양한 메소드 에서만 사용해야 합니다.
클래스 형식의 변수는 해당 클래스 형식의 인스턴스에 대한 포인터만 할당할 수 있을까요? C언어의 원리에서 생각하면, 결국 포인터일 뿐이므로 반드시 그런 것은 아닙니다.