美文网首页
iOS底层原理04 -- isKindOfClass & isM

iOS底层原理04 -- isKindOfClass & isM

作者: 阿木小丸子 | 来源:发表于2020-11-30 12:18 被阅读0次

对于isKindOfClass & isMemberOfClass的理解,我们可以通过下面的示例来看:

  • iskindOfClass & isMemberOfClass 类方法调用
        BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
        BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];     
        BOOL re3 = [(id)[WZPerson class] isKindOfClass:[WZPerson class]];       
        BOOL re4 = [(id)[WZPerson class] isMemberOfClass:[WZPerson class]];     
        NSLog(@" \n re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);
  • iskindOfClass & isMemberOfClass 实例方法调用
        BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];    
        BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];     
        BOOL re7 = [(id)[WZPerson alloc] isKindOfClass:[WZPerson class]];       
        BOOL re8 = [(id)[WZPerson alloc] isMemberOfClass:[WZPerson class]];     
        NSLog(@" \n re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);

最终的打印结果为:

2020-11-30 11:29:01.705430+0800 WZTarget[3249:117241]  
 re1 :1
 re2 :0
 re3 :0
 re4 :0
2020-11-30 11:29:01.705830+0800 WZTarget[3249:117241]  
 re5 :1
 re6 :1
 re7 :1
 re8 :1
Program ended with exit code: 0

源码分析

isKindOfClass源码:

//--isKindOfClass---类方法、对象方法
//+ isKindOfClass:第一次比较是 获取类的元类 与 传入类对比,再次之后的对比是获取上次结果的父类 与 传入 类进行对比
+ (BOOL)isKindOfClass:(Class)cls {
    // 获取类的元类 vs 传入类
    // 根元类 vs 传入类
    // 根类 vs 传入类
    // 举例:LGPerson vs 元类 (根元类) (NSObject)
    for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

//- isKindOfClass:第一次是获取对象类 与 传入类对比,如果不相等,后续对比是继续获取上次 类的父类 与传入类进行对比
- (BOOL)isKindOfClass:(Class)cls {
/*
获取对象的类 vs 传入的类 
父类 vs 传入的类
根类 vs 传入的类
nil vs 传入的类
*/
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

isMemberOfClass源码:

//-----类方法
//+ isMemberOfClass : 获取类的元类,与 传入类对比
+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}
//-----实例方法
//- isMemberOfClass : 获取对象的类,与 传入类对比
- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

总结:

isKindOfClass:

  • 类方法:类的元类(isa)-> 根元类(父类)-> 根类(父类)-> nil(父类) VS 传入类
  • 对象方法:对象的类 -> 父类 -> 根类 -> nil VS 传入类

isMemberOfClass:

  • 类方法:类的元类 VS 传入类
  • 对象方法:对象的类 VS 传入类
注:然后通过断点调试,isMemberOfClass 的类方法 和 实例方法的流程是正常的,会走到上面分析的源码,而isKindOfClass根本不会走到上面分析的源码中(!!!注意这里,这是一个坑点),而是会走到下面这个源码中,其类方法和实例方法都是走到objc_opt_isKindOfClass方法源码中
  • objc_opt_isKindOfClass方法源码如下
// Calls [obj isKindOfClass]
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
    if (slowpath(!obj)) return NO;
    //获取isa,
    //如果obj 是对象,则isa是类,
    //如果obj是类,则isa是元类
    Class cls = obj->getIsa(); 
    if (fastpath(!cls->hasCustomCore())) {
        // 如果obj 是对象,则在类的继承链进行对比,
        // 如果obj是类,则在元类的isa中进行对比
        for (Class tcls = cls; tcls; tcls = tcls->superclass) { 
            if (tcls == otherClass) return YES;
        }
        return NO;
    }
#endif
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}

为什么会这样呢?主要是因为在llvm中编译时对其进行了优化处理

  • 如果obj 是对象,则isa是类,则在类的继承链进行对比
  • 如果obj是类,则isa是元类,则在元类的isa中进行对比

案例代码执行结果分析
根据源码的分析,来分析代码执行的结果为什么是0或者1

使用类方法结果解析:
  • re1 :1 ,是 NSObject 与 NSObject 的对比,使用 +isKindOfClass

NSObject(传入类,即根类) vs NSObject的元类即根元类-- 不相等
NSObject(传入类,即根类) vs 根元类的父类即根类 -- 相等,返回1

  • re2 :0 ,是 NSObject 与 NSObject 的对比,使用 +isMemberOfClass

NSObject根类(传入类) vs NSObject的元类即根元类 -- 不相等

  • re3 :0 ,是 LGPerson 与 LGPerson 的对比,使用 +isKindOfClass

LGPerson(传入类) vs LGPerson的元类即元类LGPerson -- 不相等
LGPerson(传入类) vs 元类LGPerson的父类即根元类 -- 不相等
LGPerson(传入类) vs 根元类的父类即根类 -- 不相等
LGPerson(传入类) vs 根类的父类即 nil -- 不相等

  • re4 :0 ,是 LGPerson 与 LGPerson 的对比,使用 +isMemberOfClass

LGPerson(传入类) vs 元类 -- 不相等

使用实例方法结果解析:
  • re5 :1 ,是 NSObject对象 与 NSObject 的对比,使用 -isKindOfClass

NSObject(传入类,即根类) vs 对象的isa即NSObject根类 -- 相等

  • re6 :1 ,是 NSObject对象 与 NSObject 的对比,使用 -isMemberOfClass

NSObject(传入类,即根类) vs 对象的类即NSObject根类 -- 相等

  • re7 :1 ,是 LGPerson对象 与 LGPerson 的对比,使用 -isKindOfClass

LGPerson(传入类) vs 对象的isa即LGPerson -- 相等

  • re8 :1 ,是 LGPerson对象 与 LGPerson 的对比,使用 -isMemberOfClass

LGPerson(传入类) vs 对象的类即LGPerson -- 相等

相关文章

网友评论

      本文标题:iOS底层原理04 -- isKindOfClass & isM

      本文链接:https://www.haomeiwen.com/subject/ejsrwktx.html