An introduction to Objective-C Meta Class

An introduction to Objective-C Meta Class

First, let's have a look at the base class NSObject.

@interface NSObject <NSObject> { //implement protocol NSObject

Class isa; //point to meta class, all instances of NSObject share the same meta class.

}

+ (void)load;

+ (void)initialize;

- (id)init;

+ (id)new;

+ (id)allocWithZone:(NSZone *)zone;

+ (id)alloc;

- (void)dealloc;

+ (Class)superclass;

+ (Class)class;

...

@end

Class is defined as:

typedef struct objc_class *Class;

struct objc_class {

Class isa;

#if !__OBJC2__

Class super_class OBJC2_UNAVAILABLE;

const char *name OBJC2_UNAVAILABLE;

long version OBJC2_UNAVAILABLE;

long info OBJC2_UNAVAILABLE;

long instance_size OBJC2_UNAVAILABLE;

struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;

struct objc_method_list **methodLists OBJC2_UNAVAILABLE;

struct objc_cache *cache OBJC2_UNAVAILABLE;

struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;

#endif

} OBJC2_UNAVAILABLE;

objc_class is the meta class.

id is defined as:

typedef struct objc_object {

Class isa;

} *id;

id is an pointer pointed to struct obj_object very similar with the definition of NSObject.

//class TestA

@interface TestA : NSObject {

int a;

}

+ (id)alloc;

+ (void)initialize;

@end

@implementation TestA

+ (void)load

{

printf("load TestA. %s %#x\n", [[self description] UTF8String], self);

}

+ (id)alloc

{

self = [super alloc];

printf("alloc TestA. %s %#x\n", [[self description] UTF8String], self);

return self;

}

+ (void)initialize

{

printf("initialize TestA. %s %#x\n", [[self description] UTF8String], self);

}

- (id)init

{

self = [super init];

if(self)

{

printf("init TestA. %s %#x isa=%#x\n", [[self description] UTF8String], self, isa);

}

return self;

}

@end

//End of TestA

//class TestB

@interface TestB : TestA {

int b;

}

+ (id)alloc;

+ (void)initialize;

@end

@implementation TestB

+ (void)load

{

printf("load TestB. %s %#x\n", [[self description] UTF8String], self);

}

+ (id)alloc

{

self = [super alloc];

printf("alloc TestB. %s %#x\n", [[self description] UTF8String], self);

return self;

}

+ (void)initialize

{

printf("initialize TestB. %s %#x\n", [[self description] UTF8String], self);

}

- (id)init

{

self = [super init];

if(self)

{

printf("init TestB. %s %#x isa=%#x\n", [[self description] UTF8String], self, isa);

}

return self;

}

@end

//End of TestB

//Testing example

TestB *b1 = [[TestB alloc] init];

TestB *b2 = [[TestB alloc] init];

TestA *a1 = [[TestA alloc] init];

Output:

initialize TestA. TestA 0xd634

load TestA. TestA 0xd634

initialize TestB. TestB 0xd65c

load TestB. TestB 0xd65c

alloc TestA. <TestB: 0x4e317f0> 0x4e317f0

alloc TestB. <TestB: 0x4e317f0> 0x4e317f0

init TestA. <TestB: 0x4e317f0> 0x4e317f0 isa=0xd65c

init TestB. <TestB: 0x4e317f0> 0x4e317f0 isa=0xd65c

alloc TestA. <TestB: 0x4e369e0> 0x4e369e0

alloc TestB. <TestB: 0x4e369e0> 0x4e369e0

init TestA. <TestB: 0x4e369e0> 0x4e369e0 isa=0xd65c

init TestB. <TestB: 0x4e369e0> 0x4e369e0 isa=0xd65c

alloc TestA. <TestA: 0x4e34930> 0x4e34930

init TestA. <TestA: 0x4e34930> 0x4e34930 isa=0xd634

From the outputs, some rules can be concluded:

1. In class method, such as initialize, load, alloc. self is the address of meta class, in another word, a pointer to struct objc_class.

2. The first time a class is referenced, its meta class will only be initialized and loaded once.

3. All instances of class objects share a meta class.

4. TestB inherits from TestA. The meta class address of TestB is 0xd65c. The meta class address of TestA is 0xd634. So TestB.isa->super_class = 0xd634. so TestB can call super's methods. All methods and meta infomations are stored in isa.