代码分析
先看一个面试题
BOOL res1 = [[NSObject class]isKindOfClass:[NSObject class]];
BOOL res2 = [[NSObject class]isMemberOfClass:[NSObject class]];
BOOL res3 = [[LGPersonModel class]isKindOfClass:[LGPersonModel class]];
BOOL res4 = [[LGPersonModel class]isMemberOfClass:[LGPersonModel class]];
BOOL res5 = [[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL res6 = [[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL res7 = [[LGPersonModel alloc] isKindOfClass:[LGPersonModel class]];
BOOL res8 = [[LGPersonModel alloc] isMemberOfClass:[LGPersonModel class]];
NSLog(@"--%d--%d--%d--%d",res1,res2,res3,res4);
NSLog(@"--%d--%d--%d--%d",res5,res6,res7,res8);
运行后打印结果如下:
2020-06-05 11:38:34.555887+0800 demo[3933:66176] --1--0--0--0
2020-06-05 11:38:34.555991+0800 demo[3933:66176] --1--1--1--1
不知道结果是否跟你预测的一样,如果不清楚原因,我们就继续往下分析。
isKindOfClass
先看一下底层源码
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
这里有一个方法 object_getClass
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
inline Class
objc_object::getIsa()
{
if (!isTaggedPointer()) return ISA();
uintptr_t ptr = (uintptr_t)this;
if (isExtTaggedPointer()) {
uintptr_t slot =
(ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
return objc_tag_ext_classes[slot];
} else {
uintptr_t slot =
(ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
return objc_tag_classes[slot];
}
}
inline Class
objc_object::ISA()
{
assert(!isTaggedPointer());
#if SUPPORT_INDEXED_ISA
if (isa.nonpointer) {
uintptr_t slot = isa.indexcls;
return classForIndex((unsigned)slot);
}
return (Class)isa.bits;
#else
return (Class)(isa.bits & ISA_MASK);
#endif
}
通过之前iOS 底层原理 - isa原理中isa的指向分析,可以得知:
当前的objc若是实例对象,那么(isa.bits & ISA_MASK)返回的结果必定是当前实例对象的所对应的类。
当前的objc若是类对象,那么(isa.bits & ISA_MASK)返回的结果必定是当前类对象所对应的元类。
isKindOfClass类方法底层函数实际上就是一个for循环,通过继承链往上查找
object_getClass((id)self),当前objc是一个类对象,那么获取的类就是当前类的元类,如果objc是一个实例对象,那么获取的就是当前的类。
分析上面代码
[[NSObject class]isKindOfClass:[NSObject class]];
第一步查找NSObject的元类,匹配NSObject类,不匹配,进入循环根据NSObject元类,查找superclass,获取NSObject类,匹配NSObject类,成功。
[[LGPersonModel class]isKindOfClass:[LGPersonModel class]];
第一步查找LGPersonModel的元类,匹配LGPersonModel类,不匹配,进入循环,查找LGPersonModel的元类的superclass,获取NSObject元类,匹配XDPerson类,失败。继续进入循环,查找NSObject元类的superclass,获取NSObject类,不匹配失败。继续进入循环,查找NSObject类的superclass,获取nil,跳出循环,匹配失败。
[[NSObject alloc] isKindOfClass:[NSObject class]];
第一步,查找NSObject类,匹配NSObject类,匹配。
[[LGPersonModel alloc] isKindOfClass:[LGPersonModel class]];
第一步,查找LGPersonModel类,匹配LGPersonModel类,匹配。
isMemberOfClass 分析
我们先看一下底层实现
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
可以发现它跟isKindOfClass的区别在于,它不走循环,只找当前的。
分析上面的代码
[[NSObject class]isMemberOfClass:[NSObject class]];
获取的NSObject的元类,匹配NSObject类,不匹配。
[[LGPersonModel class]isMemberOfClass:[LGPersonModel class]];
获取的是LGPersonModel的元类,匹配LGPersonModel类,不匹配。
[[NSObject alloc] isMemberOfClass:[NSObject class]];
获取的是NSObject类,匹配NSObject类,匹配。
[[LGPersonModel alloc] isMemberOfClass:[LGPersonModel class]];
获取的是LGPersonModel类,匹配LGPersonModel类,匹配。
网友评论