您的位置:首页 > 移动开发 > Objective-C

刨根问底Objective-C Runtime(2)- Object & Class & Meta Class

2014-11-19 14:35 726 查看
原文地址:http://chun.tips/blog/2014/11/05/bao-gen-wen-di-objective%5Bnil%5Dc-runtime-(2)%5Bnil%5D-object-and-class-and-meta-class/

上一篇笔记讲述了objcruntime中Self和Super的细节,本篇笔记主要是讲述objcruntime中关于Object&Class&
MetaClass的细节。


习题内容

下面代码的运行结果是?
@interfaceSark:NSObject
@end

@implementationSark
@end

intmain(intargc,constchar*argv[]){
@autoreleasepool{
BOOLres1=[(id)[NSObjectclass]isKindOfClass:[NSObjectclass]];
BOOLres2=[(id)[NSObjectclass]isMemberOfClass:[NSObjectclass]];

BOOLres3=[(id)[Sarkclass]isKindOfClass:[Sarkclass]];
BOOLres4=[(id)[Sarkclass]isMemberOfClass:[Sarkclass]];

NSLog(@"%d%d%d%d",res1,res2,res3,res4);
}
return0;
}
[/code]

运行结果为:
2014-11-0514:45:08.474Test[9412:721945]1000
[/code]


这里先看几个概念


什么是id


id在objc.h中定义如下:
///Apointertoaninstanceofaclass.
typedefstructobjc_object*id;
[/code]

就像注释中所说的这样id是指向一个objc_object结构体的指针。

id
这个struct的定义本身就带了一个*,所以我们在使用其他NSObject类型的实例时需要在前面加上*,而使用id时却不用。


那么objc_object又是什么呢


objc_object在objc.h中定义如下:
///Representsaninstanceofaclass.
structobjc_object{
Classisa;
};
[/code]

这个时候我们知道Objective-C中的object在最后会被转换成C的结构体,而在这个struct中有一个isa指针,指向它的类别Class。

那么什么是Class呢


在objc.h中定义如下:
///AnopaquetypethatrepresentsanObjective-Cclass.
typedefstructobjc_class*Class;
[/code]

我们可以看到Class本身指向的也是一个C的struct
objc_class


继续看在runtime.h中
objc_class
定义如下:
structobjc_class{
ClassisaOBJC_ISA_AVAILABILITY;
#if!__OBJC2__
Classsuper_classOBJC2_UNAVAILABLE;
constchar*nameOBJC2_UNAVAILABLE;
longversionOBJC2_UNAVAILABLE;
longinfoOBJC2_UNAVAILABLE;
longinstance_sizeOBJC2_UNAVAILABLE;
structobjc_ivar_list*ivarsOBJC2_UNAVAILABLE;
structobjc_method_list**methodListsOBJC2_UNAVAILABLE;
structobjc_cache*cacheOBJC2_UNAVAILABLE;
structobjc_protocol_list*protocolsOBJC2_UNAVAILABLE;
#endif
}OBJC2_UNAVAILABLE;
[/code]

该结构体中,isa指向所属Class,super_class指向父类别。

继续看


下载objc源代码,在objc-runtime-new.h中,我们发现
objc_class
有如下定义:
structobjc_class:objc_object{
//ClassISA;
Classsuperclass;
...
...
}
[/code]

豁然开朗,我们看到在Objective-C的设计哲学中,一切都是对象。Class在设计中本身也是一个对象。而这个Class对象的对应的类,我们叫它
Meta
Class
。即Class结构体中的isa指向的就是它的
Meta
Class


MetaClass


根据上面的描述,我们可以把
Meta
Class
理解为
一个Class对象的Class
。简单的说:

当我们发送一个消息给一个NSObject对象时,这条消息会在对象的类的方法列表里查找
当我们发送一个消息给一个类时,这条消息会在类的MetaClass的方法列表里查找

而MetaClass本身也是一个Class,它跟其他Class一样也有自己的isa和super_class指针。看下图:



每个Class都有一个isa指针指向一个唯一的MetaClass
每一个MetaClass的isa指针都指向最上层的MetaClass(图中的NSObject的MetaClass)
最上层的Meta
Class的isa指针指向自己,形成一个回路

每一个MetaClass的superclass指针指向它原本Class的SuperClass的MetaClass。
但是最上层的Meta
Class的SuperClass指向NSObjectClass本身

最上层的NSObjectClass的superclass指向nil


解惑

为了更加清楚的知道整个函数调用过程,我们使用
clang
-rewrite-objcmain.m
重写,可获得如下代码:
BOOLres1=((BOOL(*)(id,SEL,Class))(void*)objc_msgSend)((id)((Class(*)(id,SEL))(void*)objc_msgSend)((id)objc_getClass("NSObject"),sel_registerName("class")),sel_registerName("isKindOfClass:"),((Class(*)(id,SEL))(void*)objc_msgSend)((id)objc_getClass("NSObject"),sel_registerName("class")));

BOOLres2=((BOOL(*)(id,SEL,Class))(void*)objc_msgSend)((id)((Class(*)(id,SEL))(void*)objc_msgSend)((id)objc_getClass("NSObject"),sel_registerName("class")),sel_registerName("isMemberOfClass:"),((Class(*)(id,SEL))(void*)objc_msgSend)((id)objc_getClass("NSObject"),sel_registerName("class")));

BOOLres3=((BOOL(*)(id,SEL,Class))(void*)objc_msgSend)((id)((Class(*)(id,SEL))(void*)objc_msgSend)((id)objc_getClass("Sark"),sel_registerName("class")),sel_registerName("isMemberOfClass:"),((Class(*)(id,SEL))(void*)objc_msgSend)((id)objc_getClass("NSObject"),sel_registerName("class")));

BOOLres4=((BOOL(*)(id,SEL,Class))(void*)objc_msgSend)((id)((Class(*)(id,SEL))(void*)objc_msgSend)((id)objc_getClass("Sark"),sel_registerName("class")),sel_registerName("isMemberOfClass:"),((Class(*)(id,SEL))(void*)objc_msgSend)((id)objc_getClass("NSObject"),sel_registerName("class")));
[/code]

先看前两个调用:


最外层是
objc_msgSend
函数,转发消息。
函数第一个参数是
(id)((Class
(*)(id,SEL))(void*)objc_msgSend)((id)objc_getClass("NSObject"),sel_registerName("class"))

函数第二个参数是转发的selector
函数第三个参数是
((Class
(*)(id,SEL))(void*)objc_msgSend)((id)objc_getClass("NSObject"),sel_registerName("class"))


我们注意到第一个参数和第三个参数对应重写的是
[NSObject
class]
,即使用
objc_msgSend

NSObjectClass发送@selector(class)这个消息

打开objc源代码,在Object.mm中发现
+
(Class)class
实现如下:
+(Class)class{
returnself;
}
[/code]

所以即返回Class类的对象本身。看如下输出:
NSLog(@"%p",[NSObjectclass]);
NSLog(@"%p",[NSObjectclass]);

2014-11-0518:48:30.939Test[11682:865988]0x7fff768d40f0
2014-11-0518:48:30.940Test[11682:865988]0x7fff768d40f0
[/code]

继续打开objc源代码,在Object.mm中,我们发现
isKindOfClass
的实现如下:
-(BOOL)isKindOf:aClass
{
Classcls;
for(cls=isa;cls;cls=cls->superclass)
if(cls==(Class)aClass)
returnYES;
returnNO;
}
[/code]

对着上面MetaClass的图和实现,我们可以看出

当NSObjectClass对象第一次进行比较时,得到它的isa为NSObject的MetaClass,这个时候NSObjectMetaClass和NSObjectClass不相等。
然后取NSObject的MetaClass的Superclass,这个时候又变成了NSObjectClass,所以返回相等

所以上述第一个输出结果是YES。

我们在看下‘isMemberOfClass’的实现:
-(BOOL)isMemberOf:aClass
{
returnisa==(Class)aClass;
}
[/code]

综上所述,当前的isa指向NSObject的MetaClass,所以和NSObjectClass不相等。

所以上述第二个输出结果为NO。

继续看后面两个调用:


SarkClass的isa指向的是Sark的MetaClass,和SarkClass不相等
SarkMetaClass的superclass指向的是NSObjectMetaClass,和SarkClass不相等
NSObjectMetaClass的superclass指向NSObjectClass,和SarkClass不相等
NSObjectClass的superclass指向nil,和SarkClass不相等

所以后面两个调用的结果都输出为NO。

下一篇博客的主要分享的内容是关于
ObjectiveCRuntime中消息和Category的学习笔记。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: