Announcements‎ > ‎

Objective-C 최상위 클래스

posted Jan 22, 2009, 7:43 PM by Unknown user   [ updated Jan 22, 2009, 7:47 PM ]

Objective-C는 컴파일러가 생성하는 객체의 구조에 접근 가능하게 하는 API를 제공한다. 이를 이용하면 GNU Objective-C의 Object나 MacOS X의 NSObject같은 최상위 클래스를 쉽게 작성할 수 있다. 반드시 그렇게 해야 할 이유는 없지만 말이다.

API를 사용하려면 다음의 파일들을 #include 해야 한다.

 

  • objc/objc.h
  • objc/objc-api.h
  • objc/objc-class.h (MacOS X)

 

Objective-C가 생성하는 모든 객체들은 헤더 부분에 클래스 객체에 대한 포인터를 가지며, 데이터 부분은 클래스 정의에 따라 달라지게 된다. 객체의 헤더 부분은 struct objc_object에 정의 되어 있다.

/* GNU Objective-C - objc/objc.h */

struct objc_object
{
    struct objc_class* class_pointer;
};

MacOS X에서는 class_pointer대신 isa라는 이름이 사용된다.

struct objc_class는 클래스 객체의 구조를 정의한다. 클래스 역시 객체이므로 메타클래스라고 하는 자신의 클래스 객체에 대한 포인터를 가지며, 크기, 이름, 부모 클래스등 생성할 객체에 대한 여러 가지 정보를 담고 있다.

/* GNU Objective-C - objc/objc.h */
 
struct objc_class
{
    struct objc_class* class_pointer;
    struct objc_class* super_class;
    const char* name;
    long version;
    unsigned long info;
    long instance_size;
    struct objc_ivar_list* ivars;
    struct objc_method_list* methods;
    struct sarray* dtable;
    struct objc_class* subclass_list;
    struct objc_class* sibling_class;
    struct objc_protocol_list *protocols; void* gc_object_type;
};

최상위 클래스는 클래스 포인터를 초기화 하고 객체의 생성과 소멸을 담당하는 메서드들을 제공해야 한다. GNU Objective-C의 Object처럼 alloc, init, free, new를 작성해보자.

/* Object.h */
 
#include <objc/objc.h>
#include <objc/objc-api.h>
#ifdef __APPLE__
#include <objc/objc-class.h>
#endif
 
@interface Object
{
    struct objc_class* isa;
}
 
+ (id) alloc;
+ (id) new;
- (id) init;
- (void) free;
 
@end
  • isa - 클래스 포인터
  • alloc - 객체가 필요한 메모리 공간을 할당한다.
  • free - 객체가 사용한 메모리 공간을 해제한다.
  • init - 객체를 초기화 한다.
  • new - [[object alloc] init]

 

alloc를 제외한 나머지는 다음과 같이 간단하게 구현될 수 있다.

/* Object.m */
 
#include "Object.m"
#include <stdlib.h>
 
@implementation Object
 
+ (id) alloc
{
    return alloc_object (self);
}
 
+ (id) new
{
    id obj = [self alloc];
    if (obj == nil) return nil;
    return [obj init];
}
 
- (id) init
{
    return self;
}
 
- (void) free
{
    if (self != nil) free (self);
}
@end
객체가 필요한 공간을 할당하려면 객체의 크기를 알아야 한다. 객체의 크기는 클래스의 instance_size 필드에 저장이 되는데, 실제 필요한 크기는 여기에 헤더부분(클래스포인터)의 크기를 포함해야 한다.
/* Object.m */
 
static struct objc_object* alloc_object (struct objc_class* class)
{
    size_t size;
    struct objc_object* obj;
 
    /* 객체가 필요로 하는 공간의 크기 */
    size = sizeof(struct objc_object) + class->instance_size;
 
    /* 공간을 할당한다 */
    obj = (struct objc_object*)calloc(1, size);
    if (obj == NULL) return nil;
 
    /* MacOS X는 class_pointer대신 isa라는 이름을 사용하므로 #ifdef로 처리한다 */
#ifdef __APPLE__
    obj->isa = class;
#else
    obj->class_pointer = class;
#endif
    return obj;
}

MacOS X는 추가적으로 forward:sel:메서드를 필요로 한다.

#ifdef __APPLE__
- (id) forward: (SEL)sel: (marg_list)args
{
    return self;
}
#endif

이제 위에서 만든 최상위 클래스를 사용해 보도록 하자.

#include "Object.h"
#include <stdio.h>
 
@interface Child: Object
{
    int a;
}
 
- (id) init;
- (void) print;
@end
 
@implementation Child
- (id) init
{
    [super init];
    a = 2871;
    return self;
}
 
- (void) print
{
    printf ("a = %d\n", a);
}
 
@end
 
int main ()
{
    id t;
 
    t = [[Child alloc] init]; /* 개체를 생성하고 초기화 한다 */
    [t print]; /* print메시지를 보낸다 */
    [t free]; /* 개체를 없앤다 */
    return 0;
}
 
Comments