meta-class

What is a meta-class in Objective-C?

http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html

January 17, 2010by Matt Gallagher

Tags:Objective-C,Foundation

In this post, I look at one of the

stranger concepts in Objective-C — the meta-class. Every class in

Objective-C has its own associated meta-class but since you rarely ever

use a meta-class directly, they can remain enigmatic. I'll start by

looking at how to create a class at runtime. By examining the "class

pair" that this creates, I'll explain what the meta-class is and also

cover the more general topic of what it means for data to be an object

or a class in Objective-C.Creating a class at runtime

The following code creates a new subclass of NSErrorat runtime and adds one method to it:

Class newClass = objc_allocateClassPair([NSErrorclass],"RuntimeErrorSubclass",0);

class_addMethod(newClass,@selector(report),(IMP)ReportFunction,"v@:");

objc_registerClassPair(newClass);

The method added uses the function namedReportFunctionas its implementation, which is defined as follows:

void ReportFunction(idself,SEL_cmd)

{

       NSLog(@"This object is %p.",self);

       NSLog(@"Class is %@, and super is %@.",[selfclass],[selfsuperclass]);

       ClasscurrentClass=[selfclass];

       for(inti=1;i<5;i++){

                NSLog(@"Following the isa pointer %d times gives %p",i,currentClass);

                 currentClass=object_getClass(currentClass);

}

NSLog(@"NSObject's class is %p",[NSObjectclass]);

NSLog(@"NSObject's meta class is %p",object_getClass([NSObjectclass]));

}

On the surface, this is all pretty simple. Creating a class at runtime is just three easy steps:

1,Allocate storage for the "class pair" (usingobjc_allocateClassPair).

2,Add methods and ivars to the class as needed (I've added one method usingclass_addMethod).

3,Register the class so that it can be used (usingobjc_registerClassPair).

However, the immediate question is: what is a "class pair"? The function objc_allocateClassPair only returns one value: the class. Where is the other half of the pair?

I'm sure you've guessed that the other half of the pair is the

meta-class (it's the title of this post) but to explain what that is and

why you need it, I'm going to give some background on objects and

classes in Objective-C.

What is needed for a data structure to be an object?

Every object has a class. This is a fundamental object-oriented

concept but in Objective-C, it is also a fundamental part of the data.

Any data structure which has a pointer to a class in the right location

can be treated as an object.

In Objective-C, an object's class is determined by its isa pointer. The isa pointer points to the object's Class.

In fact, the basic definition of an object in Objective-C looks like this:

typedef struct objc_object {

          Class   isa;

}*id;

What this says is: any structure which starts with a pointer to aClassstructure can be treated as anobjc_object.

The most important feature of objects in Objective-C is that you can send messages to them:

[@"stringValue" writeToFile:@"/file.txt" atomically:YES encoding:NSUTF8StringEncodingerror:NULL];

This works because when you send a message to an Objective-C object (like theNSCFStringhere), the runtime follows object's isa pointer to get to the object's Class(theNSCFStringclass in this case). The Class then contains a list of the Methods which apply to all objects of that Class and a pointer to the super class to look up inherited methods. The runtime looks through the list of Methods on the Class and super classes to find one that matches the message selector (in the above case,writeToFile:atomically:encoding:erroronNSString). The runtime then invokes the function (IMP) for that method.

The important point is that the Class defines the messages that you can send to an object.

What is a meta-class?

Now, as you probably already know, a Class in Objective-C is also an object. This means that you can send messages to a Class.

NSStringEncoding defaultStringEncoding = [NSStringdefaultStringEncoding];

In this case,defaultStringEncoding is sent to the NSString class.

This works because everyClassin Objective-C is an object itself. This means that the Class structure must start with an isa pointer so that it is binary compatible with the objc_object structure I showed above and the next field in the structure must be a pointer to the super class(or nil for base classes).

As I showed last week, there are a couple different ways that a Class can be defined, depending on the version of the runtime you are running, but yes, they all start with an isa field followed by asuperclassfield.

typedef struct objc_class*Class;

structobjc_class{

       Class isa;

     Class super_class;/* followed by runtime specific details... */

};

However, in order to let us invoke a method on aClass, the isa pointer of the Class must itself point to a Class structure and that Class structure must contain the list of Methods that we can invoke on the Class.

This leads to the definition of a meta-class: the meta-class is the class for a Class object.

Simply put:

When you send a message to an object, that message is looked up in the method list on the object's class.

When you send a message to a class, that message is looked up in the method list on the class' meta-class.

The meta-class is essential because it stores the class methods for a Class. There must be a unique meta-class for every Class because every Class has a potentially unique list of class methods.

What is the class of the meta-class?

The meta-class, like the Class before it, is also an object. This means that you can invoke methods on it too. Naturally, this means that it must also have a class.

All meta-classes use the base class' meta-class (the meta-class of the top Class in their inheritance hierarchy) as their class. This means that for all classes that descend from NSObject(most classes), the meta-class has the NSObject meta-class as its class.

Following the rule that all meta-classes use the base class' meta-class as their class, any base meta-classes will be its own class (theirisapointer points to themselves). This means that the isa pointer on the NSObject meta-class points to itself (it is an instance of itself).

Inheritance for classes and meta-classes

In the same way that the Class points to the superclass with its super_class pointer, the meta-class points to the meta-class of the Class' super_class using its own super_class pointer.

As a further quirk, the base class' meta-class sets its super_class to the base class itself.

The result of this inheritance hierarchy is that all instances,

classes and meta-classes in the hierarchy inherit from the hierarchy's

base class.

For all instances, classes and meta-classes in the NSObject hierarchy, this means that all NSObject instance methods are valid. For the classes and meta-classes, all NSObject class methods are also valid.

All this is pretty confusing in text.Greg Parker has put together an excellent diagram of instances, classes, meta-classes and their super classes and how they all fit together.

Experimental confirmation of this

To confirm all of this, let's look at the output of the ReportFunctionI gave at the start of this post. The purpose of this function is to follow theisapointers and log what it finds.

To run theReportFunction, we need to create an instance of the dynamically created class and invoke thereportmethod on it.

id instanceOfNewClass = [[newClass alloc] initWithDomain:@"someDomain"code:0userInfo:nil];[instanceOfNewClass performSelector:@selector(report)];

[instanceOfNewClass release];

Since there is no declaration of the report method, I invoke it using performSelector:so the compiler doesn't give a warning.

The ReportFunction will now traverse through the isa pointers and tell us what objects are used as the class, meta-class and class of the meta-class.

Getting the class of an object:the ReportFunction uses object_getClass to follow the isa pointers because the isa pointer is a protected member of the class (you can't directly access other object'sisapointers). The ReportFunction does not use the class method to do this because invoking the classmethod on a Class object does not return the meta-class, it instead returns the Class again (so [NSString class] will return the NSString class instead of the NSString meta-class).

This is the output (minus NSLog prefixes) when the program runs:

This object is0x10010c810.Class is RuntimeErrorSubclass,and super is NSError.

Following the isa pointer1 times gives 0x10010c600

Following the isa pointer2 times gives 0x10010c630

Following the isa pointer3 times gives 0x7fff71038480

Following the isa pointer4 times gives 0x7fff71038480

NSObject's classis 0x7fff710384a8

NSObject's metaclass is 0x7fff71038480

Looking at the addresses reached by following the isa value repeatedly:

the object is address0x10010c810.

the class is address0x10010c600.

the meta-class is address0x10010c630.

the meta-class's class (i.e. theNSObjectmeta-class) is address 0x7fff71038480.

the NSObject meta-class' class is itself.

The value of the addresses is not really important except that it shows the progress from class to meta-class to NSObject meta-class as discussed.

Conclusion

The meta-class is the class for a Class object. Every Class has its own unique meta-class (since every Class can have its own unique list of methods). This means that all Class objects are not themselves all of the same class.

The meta-class will always ensure that the Classobject has all the instance and class methods of the base class in the hierarchy, plus all of the class methods in-between. For classes descended from NSObject, this means that all the NSObject instance and protocol methods are defined for allClass(and meta-class) objects.

All meta-classes themselves use the base class' meta-class (NSObject meta-class for NSObject hierarchy classes) as their class, including the base level meta-class which is the only self-defining class in the runtime.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,176评论 5 469
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,190评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,232评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,953评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,879评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,177评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,626评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,295评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,436评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,365评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,414评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,096评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,685评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,771评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,987评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,438评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,032评论 2 341

推荐阅读更多精彩内容

  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 9,291评论 0 23
  • 2015年5月1日bigbang新专辑《M》发行,此后保持每月一专的速度发行新曲。这是时隔两年的回归,全球的VI...
    偏执狂9693阅读 356评论 0 2
  • 《玄奘西行》,区别于传统民乐,突破了常规的民族器乐表现形式,它将舞台表演和乐器演奏有机结合融合一起,带入情绪,通过...
    穆小哥阅读 5,670评论 0 0
  • 突然有了想写简书的冲动,也许只是一时心血来潮也许是真的成熟长大了,更也许只是心中有事无人能诉。很想有一个能说心里话...
    SOMETHING都还来得及阅读 213评论 3 1