面试题-isKindOf vs isMemberOf

1,836 阅读2分钟

  首先我们来看看isKindOf、isMemberOf作为实例方法和类方法实现的源码:

+ (Class)class {
    return self;
}

- (Class)class {
    return object_getClass(self);
}
+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); 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;
}

分析:

  • +isKindOfClass作为类方法调用的时候,object_getClass传入的参数是类,返回的是元类,多层级遍历之后根元类的父类就是根类,所以isKindOfClass我们只需要判断当前调用的元类、父类和比较类是否相同即可。
  • -isKindOfClass作为实例方法调用的时候,由于此时self是一个实例对象,[self class],则返回的是当前实例对象的类,所以isKindOfClass需要判断当前调用的类、其父类和比较类是否相同即可。
+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}

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

分析:

  • +isMemberOfClass作为类方法调用的时候,object_getClass返回的是调用者的元类,所以只需要判断调用者的元类和比较类是否相等即可。
  • -isMemberOfClass作为实例方法调用的时候,就是比较调用实例的类是否和比较类相同。

eg:

BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];       // 1
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];     // 0
BOOL re3 = [(id)[TPerson class] isKindOfClass:[TPerson class]];         // 0
BOOL re4 = [(id)[TPerson class] isMemberOfClass:[TPerson class]];       // 0
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]];       // 1
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];     // 1
BOOL re7 = [(id)[TPerson alloc] isKindOfClass:[TPerson class]];         // 1
BOOL re8 = [(id)[TPerson alloc] isMemberOfClass:[TPerson class]];       // 1
NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);

我们分析一下:

[(id)[NSObject class] isKindOfClass:[NSObject class]]

  [NSObject class]返回的是NSObject类,所以我们调用的是+isKindOfClass,比较的也是[NSObject class]NSObject类,+isKindOfClass比较的是NSObject类的元类及其元类的父类是否等于NSObject类,根据isa和superClass关系图可以知道,NSObject类的元类的父类就是NSObject,和比较对象NSObject相等,所以re1 = 1。

同理,可以得出其他的结果。

最后附图一张: