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

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

2015-07-22 18:51 766 查看

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

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

习题内容

下面代码的运行结果是?

[code]@interface Sark : NSObject
@end

@implementation Sark
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
        BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];

        BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];
        BOOL res4 = [(id)[Sark class] isMemberOfClass:[Sark class]];

        NSLog(@"%d %d %d %d", res1, res2, res3, res4);
    }
    return 0;
}

运行结果为:

[code]2014-11-05 14:45:08.474 Test[9412:721945] 1 0 0 0

这里先看几个概念

什么是 id
id 在 objc.h 中定义如下:

[code]/// A pointer to an instance of a class.
typedef struct objc_object *id;

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

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


那么objc_object又是什么呢
objc_object 在 objc.h 中定义如下:

[code]/// Represents an instance of a class.
struct objc_object {
    Class isa;
};

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

那么什么是Class呢
在 objc.h 中定义如下:

[code]/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

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


继续看在runtime.h中
objc_class
定义如下:

[code]struct objc_class {
    Class isa  OBJC_ISA_***AILABILITY;
    #if !__OBJC2__
    Class super_class                                        OBJC2_UN***AILABLE;
    const char *name                                         OBJC2_UN***AILABLE;
    long version                                             OBJC2_UN***AILABLE;
    long info                                                OBJC2_UN***AILABLE;
    long instance_size                                       OBJC2_UN***AILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UN***AILABLE;
    struct objc_method_list **methodLists                    OBJC2_UN***AILABLE;
    struct objc_cache *cache                                 OBJC2_UN***AILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UN***AILABLE;
    #endif
} OBJC2_UN***AILABLE;

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

继续看
下载objc源代码,在 objc-runtime-new.h 中,我们发现
objc_class
有如下定义:

[code]struct objc_class : objc_object {
    // Class ISA;
    Class superclass;   
    ...
    ...
}

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


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

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

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



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

每一个Meta Class的super class指针指向它原本Class的 Super Class的Meta Class。
但是最上层的Meta
 Class的 Super Class指向NSObject Class本身

最上层的NSObject Class的super class指向 nil

解惑

为了更加清楚的知道整个函数调用过程,我们使用
clang
 -rewrite-objc main.m
重写,可获得如下代码:

[code] BOOL res1 = ((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")));

 BOOL res2 = ((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")));

 BOOL res3 = ((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")));

 BOOL res4 = ((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")));

先看前两个调用:

最外层是
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

NSObject Class 发送 @selector(class) 这个消息

打开objc源代码,在 Object.mm 中发现
+
 (Class)class
实现如下:

[code]+ (Class)class {
    return self;
}

所以即返回Class类的对象本身。看如下输出:

[code]NSLog(@"%p", [NSObject class]);
NSLog(@"%p", [NSObject class]);

2014-11-05 18:48:30.939 Test[11682:865988] 0x7fff768d40f0
2014-11-05 18:48:30.940 Test[11682:865988] 0x7fff768d40f0

继续打开objc源代码,在 Object.mm 中,我们发现
isKindOfClass
的实现如下:

[code]- (BOOL)isKindOf:aClass
{
    Class cls;
    for (cls = isa; cls; cls = cls->superclass) 
        if (cls == (Class)aClass)
            return YES;
    return NO;
}

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

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

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

我们在看下 ‘isMemberOfClass’的实现:

[code]- (BOOL)isMemberOf:aClass
{
    return isa == (Class)aClass;
}

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

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

继续看后面两个调用:

Sark Class 的isa指向的是 Sark的Meta Class,和Sark Class不相等
Sark Meta Class的super class 指向的是 NSObject Meta Class, 和 Sark Class不相等
NSObject Meta Class的 super class 指向 NSObject Class,和 Sark Class 不相等
NSObject Class 的super class 指向 nil, 和 Sark Class不相等

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

下一篇博客的主要分享的内容是关于
 Objective C Runtime中 消息和Category 的学习笔记。


本文是关于Objective C Runtime的学习笔记。有不对的地方,欢迎大家指正。
感谢@唐巧_boy@sunnyxx分享题目。
本文由@Chun发表于Chun
Tips .
版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0

分享到:2

Posted by Chun Ye Nov 5th, 2014 10:29
am objective-c runtime
刨根问底Objective-C
Runtime(3)- 消息 和 Category »

Comments

最新最早最热

9条评论
1条新浪微博



jiangzhibin_jr
您好,对于您说的isKindOf的实现,有个情况不理解,如果是给实例对象发isKindOf消息时,那个isa代表什么,比如 Sark *sark = [[Sark alloc] init]; BOOL ret = [sark isKindOf:[Sark class]]; 此时这个ret为YES
2014年11月24日回复顶转发



jiangzhibin_jr
回复 jiangzhibin_jr: 如果按照Meta Class 就应该为NO了吧 求解答 感激不尽!
2014年11月24日回复顶转发





Chun Ye
回复 jiangzhibin_jr: hi



你这里说的isa是指向Sark class,看 objc_object结构体的构造。

然后在进行isKindOf比较时,看isKindOf的实现,第一次循环比较就得出结果,所以return YES。
2014年11月25日回复顶转发



一休
你好,这个代码我不是很理解,为什么类方法里还有self

+ (Class)class {

return self;

}
2014年12月24日回复顶转发



一休
回复 一休: 这个self指的什么,我测试了下 每个类的self貌似都不一样,但是一个类的这个方法里的self地址是一样的

不是很理解~
2014年12月24日回复顶转发





Chun Ye
回复 一休: 这里是Objective-C Runtime实现的源码,在Objective-C这门语言的实现中,Class本身也是一个对象, 这里的self指向Class对象
1月3日回复顶转发举报



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: