iOS进阶

07.3-Runtime中isMemberOfClass,isK

2020-06-21  本文已影响0人  光强_上海

我们新建一个工程,创建一个Person类,示例代码如下:

Person

@interface Person : NSObject

@end


@implementation Person

@end

main函数

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Person *person = [[Person alloc] init];
        
        NSLog(@"%d", [person isMemberOfClass:[Person class]]); // 1
        NSLog(@"%d", [person isMemberOfClass:[NSObject class]]); // 0
        
        NSLog(@"%d", [person isKindOfClass:[Person class]]); // 1
        NSLog(@"%d", [person isKindOfClass:[NSObject class]]); // 1
    }
    return 0;
}

我们从main函数中的四个语句的打印,然后结合下面底层源码,我们可以看出结论:

上面的示例都是验证实例对象的用法,下面我们在验证下类对象的用法,示例代码如下:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Person *person = [[Person alloc] init];
                
        NSLog(@"%d", [Person isMemberOfClass:[Person class]]); // 0
        NSLog(@"%d", [Person isKindOfClass:[Person class]]); // 0
        
        NSLog(@"%d", [Person isMemberOfClass:object_getClass([Person class])]); // 1
        
        NSLog(@"%d", [Person isKindOfClass:object_getClass([Person class])]); // 1
        
        NSLog(@"%d", [Person isKindOfClass:object_getClass([NSObject class])]); // 1
        
        // 这个比较特殊
        NSLog(@"%d", [[Person class] isKindOfClass:[NSObject class]]); // 1
    }
    return 0;
}

我们通过上面main函数中的打印结果和下面源码分析可以得出结论:

但是对于示例NSLog(@"%d", [[Person class] isKindOfClass:[NSObject class]]); // 1比较特殊,因为我们上面总结的+isKindOfClass右边都应该是元类对象进行比较,但是此示例中右边却是类对象,为什么打印还是1?

这是因为+isKindOfClass方法是遍历进行比较,当执行object_getClass([Person class])拿到的元类对象不等于右边时,就会通过superclass指针一层层往上找,直到找到基类的元类对象时左右两边还是不相等,此时则会从基类的元类对象找到基类的类对象,如下图红框所示,这时正好左边的类对象等于右边的类对象,所以打印结果为1

isa,superclass指针查找逻辑如图:

image

isMemberOfClassisKindOfClass底层源码查看路径:objc4源码 -> NSObject.mm -> isMemberOfClass -> isKindOfClass

isMemberOfClass实例方法

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

isMemberOfClass类方法

+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}

isKindOfClass实例方法

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

isKindOfClass类方法

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

讲解示例Demo地址:https://github.com/guangqiang-liu/07.3-RunTime-isMemberOfClass-isKindOfClass

更多文章

上一篇 下一篇

猜你喜欢

热点阅读