小码哥iOS学习笔记第十五天: isKindOfClass:和isMemberOfClass:

952 阅读2分钟

一、面试题

  • 面试题: Person继承自NSObject, main函数中代码如下

  • 此时打印是什么? 为什么是这种打印?

二、isKindOfClass:和isMemberOfClass:的底层源码

  • 关于isKindOfClass:isMemberOfClass:两个方法, 底层代码是开源的

1、- (BOOL)isMemberOfClass:(Class)cls

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}
  • 可以看到方法的实现中, 是将self的类方法, 与传入的Class进行对比, 如果相同返回YES, 否则返回NO

2、- (BOOL)isKindOfClass:(Class)cls

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}
  • 可以看到方法的实现中, 是先将[self class]与传入cls对比,
    • 如果相同返回YES
    • 如果不同就会取出[[self class] supperclass]cls对比
  • 只要这个过程中有相同的情况就会返回YES, 如果最后也没有匹配成功就会返回NO

3、+ (BOOL)isMemberOfClass:(Class)cls

+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}
  • 可以看到方法的实现中, 获取了self元类对象与传入的cls进行对比, 如果相同返回YES, 否则返回NO

4、+ (BOOL)isKindOfClass:(Class)cls

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}
  • 可以看到方法的实现中, 使用self元类对象与传入的cls进行对比
    • 如果相等返回YES
    • 如果不相等, 就回取出object_getClass(self)->superclasscls对比, 依次类推
  • 只要这个过程中有相同的情况就会返回YES, 如果最后也没有匹配成功就会返回NO

  • 注意: 在上面的代码中, 有两句的结果是1
// [NSObject class] == [NSObject class]
NSLog(@"%d", [[Person class] isKindOfClass:[NSObject class]]);

// [NSObject class] == [NSObject class]
NSLog(@"%d", [[NSObject class] isKindOfClass:[NSObject class]]);
  • 在这两句中, 可以看到传入的cls参数都是[NSObject class]

那么为什么, 这两句代码的结果相等呢?

  • 在使用superclass查找父类的过程中, 如果是通过元类对象查找, 根类NSObject元类对象superclass[NSObject class]

  • 所以对于任何的元类对象, 只要一直查找元类superclass, 最终都会找到[NSOject class], 所以上面两句代码的结果是相等的

总结:
只要是isKindOfClass:方法的cls参数是[NSObject class], 那么调用者只要是NSObject或者NSObject的子类, 那么结果都是YES

三、解答面试题

// 元类对象最后会通过`superclass`找到[NSObject class], 所以结果相等, 结果是1
NSLog(@"%d", [NSObject isKindOfClass:[NSObject class]]);

// objc_getClass([NSObject class]) != [NSObject class] 结果是0
NSLog(@"%d", [NSObject isMemberOfClass:[NSObject class]]);

// objc_getClass([Person class]) != [Person class] 结果是0
NSLog(@"%d", [Person isKindOfClass:[Person class]]);

// objc_getClass([Person class]) != [Person class] 结果是0
NSLog(@"%d", [Person isMemberOfClass:[Person class]]);