OC底层原理之面试题分析

isKindOfClass 面试题分析

BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];       //
    BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];     //
    BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];       //
    BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];     //
    NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);

    BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];       //
    BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];     //
    BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];       //
    BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];     //
    NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);

本代码是在objc源码环境下编译运行的。通过运行可知结果

 re1 :1
 re2 :0
 re3 :0
 re4 :0
 re5 :1
 re6 :1
 re7 :1
 re8 :1

分析源码可知

类方法isMemberOfClass,实际上是用元类和传入的参数cls做对比
+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

实例方法isMemberOfClass,实际上是用类和传入的参数cls做对比
- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

类方法isKindOfClass,实际上是一个循环查找元类的父类,然后和参数cls 做对比的过程
+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}

实例方法isKindOfClass,实际上是一个循环查找类的父类,然后和cls 做对比的过程
- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}

注意

在最新版mac系统中,在源码isKindOfClass 方法里面打断点调试发现,断点并进不来。使用查看汇编代码的方式可以发现

在代码执行的堆栈中,isKindOfClass 实际上是进入了objc_opt_isKindOfClass方法。
在源码环境下搜索objc_opt_isKindOfClass方法,首先可以看到这样的定义
OBJC_EXPORT BOOL
objc_opt_isKindOfClass(id _Nullable obj, Class _Nullable cls)
    OBJC_AVAILABLE(10.15, 13.0, 13.0, 6.0, 5.0);

这里发现,objc_opt_isKindOfClass发放支持Mac 10.15之后版本,和iOS 13.0之后的版本。

// Calls [obj isKindOfClass]
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
    if (slowpath(!obj)) return NO;
 // 当obj是对象的时候,obj->getIsa()实际上等同于 [obj class]。 当obj是类对象的时候,obj->getIsa() 也就是获取类的元类。
    Class cls = obj->getIsa(); 
    if (fastpath(!cls->hasCustomCore())) {
        for (Class tcls = cls; tcls; tcls = tcls->getSuperclass()) { 
// 把cls赋值给tcls,并且判断tcls是否存在,如果存在则进行下面的比较。如果if 条件不成立则 tcls 等于 tcls 的父类。
            if (tcls == otherClass) return YES;
        }
        return NO;
    }
#endif
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}

通过此方法的注释可知,obj调用isKindOfClass方法的时候会执行当前的方法。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容