iOS isKindOfClass isMemberOfClass 底层源码原理解析及练习
直接看源码
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
+ (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;
}
看源码大家是不是一目了然。
实例方法
isMemberOfClass 其实就是判断是否为当前类型,精确判断,如当前对象只能为当前对象,如果拿当前对象和当前对象的父类对象调用这个方法,那么返回的是NO。
isKindOfClass 看源码,其实是遍历了当前对象的所有父类对象,意思就是说,当前对象为子类,也可以返回 yes,说白了就是判断,当前对象和要比较的对象是否为同一个对象或者为比较的对象的子类都可以返回 yes。
类方法
[Test isMemberOfClass:[Test class]];
如果我们这样去调用,会返回什么呢,我们去看上面的源码就知道了,上面的方法调用了 object_getClass((id)self) == cls;
这个,也就是object_getClass((id) Test) == [Test class];所以,意思就是判断,当前对象的元类对象,是否等于传进来的对象,所以上面的值返回为0。
原因就是在于 object_getClass 拿到的是当前类的元类.
如果我们这样改造就可以了,NSLog(@"%d",[[Test class] isMemberOfClass:object_getClass([Test class])]);
这样呢 NSLog(@"%d",[Test isKindOfClass:[Test class]]);
答案也是 0 ,以为前面也是元类,前面大后面小,将其改为 NSLog(@"%d",[Test isKindOfClass:[NSObject class]]);
这样,前小后大就可以了,或者传进来一个元类对象 就可以了 NSLog(@"%d",[Test isKindOfClass:object_getClass([Test class])]);
扩展
NSLog(@"%d",[NSObject isMemberOfClass:[NSObject class]]);
NSLog(@"%d",[NSObject isKindOfClass:[NSObject class]]);
第一个其实可以换成 NSLog(@"%d",object_getClass([NSObject class]) == [NSObject class]);
这样,就是当前类的元类是否和当前类相等,答案为0.
第二个答案为1,因为源码为从当前类的元类通过superclass指针向上找,其实NSObject 的元类通过 superClass指针向上找,最后都会回到 rootClass 也就是 NSObject,苹果官网有一张图,关于isa 和superClass指针指向的那个,基于那个理解,就好理解了,所以这里答案为1.
练习
// Test 集成 NSObject
Test *test = [[Test alloc] init];
NSLog(@"%d",[test isMemberOfClass:[Test class]]);
NSLog(@"%d",[test isKindOfClass:[Test class]]);
NSLog(@"%d",[test isMemberOfClass:[NSObject class]]);
NSLog(@"%d",[test isKindOfClass:[NSObject class]]);
NSLog(@"%d",[Test isMemberOfClass:[Test class]]);
NSLog(@"%d",[Test isKindOfClass:[Test class]]);
NSLog(@"%d",[Test isMemberOfClass:[NSObject class]]);
NSLog(@"%d",[Test isKindOfClass:[NSObject class]]);
NSLog(@"%d",[NSObject isMemberOfClass:[NSObject class]]);
NSLog(@"%d",[NSObject isKindOfClass:[NSObject class]]);
答案为 1101000101
总结一句话,如果左边为实例对象调用,右边传类对象,如果左边为类对象,右边传元类对象。