isKindOfClass:与isMemberOfClass:

前言

对于iOS开发者而言,isKindOfClass:isMemberOfClass:应该是相当熟悉的,今天我们不是要讲这两个方法的用法,而是讨论一个关于这两个方法的面试题。

正文

大家思考一下下面这个面试题:

BOOL result1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL result2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL result3 = [(id)[PYTeacher class] isKindOfClass:[PYTeacher class]];
BOOL result4 = [(id)[PYTeacher class] isMemberOfClass:[PYTeacher class]];

其实分析这个面试题,只要根据 isa 的指向图,加以分析就能得出正确的结论:

result1 = YES;
result2 = NO;
result3 = NO;
result4 = NO;

分析过程:

NSObject类对象 属于 NSObject元类NSObject元类父类NSObject类,所以result1 = YESresult2 = NO
同理:
PYTeacher类对象 属于 PYTeacher元类,但是在 PYTeacher元类继承链 中不包含 PYTeacher类,所以result3 = NOresult4 = NO

小结

本来分析到这里,这篇文章也就该结束了。但是,笔者曾亲身经历过这个面试题,也是这样分析的,但面试官始终追问一句:你有没有看过 isKindOfClass: 的实现?
今天,同样把这个问题抛给大家:你有没有看过 isKindOfClass: 的实现?

isKindOfClass:

我们可以通过 objc源码查看 isKindOfClass: 的具体实现:

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

so easy! 就这么简单!一个 for 循环而已! 😎😎😎
让我们运行一下,在isKindOfClass:里打个断点:

图1

这时,意外发生了!!!
程序并没有停在断点这里!!!
什么情况?方法为什么没有执行?😱😱😱

这个方法没有执行,肯定是出了什么问题,那能是什么问题呢?我们只是运行了一下代码而已,难道是编译器做了手脚?

LLVM

刚才我们想到了编译器,那我们就从 LLVM 里面寻找答案。我们可以在LLVM的代码里搜索isKindOfClass,会找到如下内容:

// This is the table of ObjC "accelerated dispatch" functions.  They are a set
// of objc methods that are "seldom overridden" and so the compiler replaces the
// objc_msgSend with a call to one of the dispatch functions.  That will check
// whether the method has been overridden, and directly call the Foundation 
// implementation if not.  
// This table is supposed to be complete.  If ones get added in the future, we
// will have to add them to the table.
const char *AppleObjCTrampolineHandler::g_opt_dispatch_names[] = {
    "objc_alloc",
    "objc_autorelease",
    "objc_release",
    "objc_retain",
    "objc_alloc_init",
    "objc_allocWithZone",
    "objc_opt_class",
    "objc_opt_isKindOfClass",
    "objc_opt_new",
    "objc_opt_respondsToSelector",
    "objc_opt_self",
};

注释的大体意思就是,这是个加速调度的函数表,这里面是一些很少被覆盖的objc的方法,所以编译器会用他们替换objc_msgSend。我们发现其中有一个objc_opt_isKindOfClass,我们猜测编译器会用他来替换isKindOfClass:方法。我们在 objc 的源码中搜索这个方法,并打一个断点。

图2

如图2中,果然像我们猜测的那样,调用了 objc_opt_isKindOfClass 方法,而这个方法的主要内容也是一个 for 循环,至此 isKindOfClass: 我们就分析完了。😂

isMemberOfClass

isMemberOfClass的源码如下:

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

isMemberOfClass的源码并不复杂,这里就不再赘述了。👨‍🏫

总结

当我们在调用isKindOfClass:方法的时候,编译器已经把方法替换了,实际运行的时候,会调用 objc_opt_isKindOfClass 方法,方法内部会通过一个 for 循环来追溯,对象所属的类在不在目标类的继承链中。

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