闲暇时看到一个问题。关于 isKindOfClass isMemberOfClass
一个看似很简单的问题。若要探索,源码一看就知道答案。源码objc的源码中
测试一下。
BOOL kre1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL kre2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL kre3 = [[GoodGame class] isKindOfClass:[GoodGame class]];
BOOL kre4 = [[GoodGame class] isMemberOfClass:[GoodGame class]];
BOOL kre5 = [[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL kre6 = [[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL kre7 = [[GoodGame alloc] isKindOfClass:[GoodGame class]];
BOOL kre8 = [[GoodGame alloc] isMemberOfClass:[GoodGame class]];
NSLog(@"\n k1 :%hhd\n k2 :%hhd\n k3 :%hhd\n k4 :%hhd\n k5:%hhd\n k6:%hhd\n k7:%hhd\n k8:%hhd\n ",kre1,kre2,kre3,kre4,kre5, kre6, kre7, kre8);}
答案很简单
提个疑问为什么
在看源码的过程中联想 alloc 方法,并没有在底层调用alloc 。通过符号断点来查看。
真的神头鬼脸,没调用
isKindOfClass 而是 objc_opt_isKindOfClass。
源码搜索一下objc_opt_isKindOfClass
objc_opt_isKindOfClass
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
if (slowpath(!obj)) return NO;
/// isa 实例对象的isa -> 类对象 -> 元类对象 -> 根元类(NSObject) -> 自身(NSObject)
/// Superclass 子类 -> 父类对象 -> NSObject -> nil
/// 函数流程 obj->isa-> 如果 相等结束 否则 Superclass 继续
Class cls = obj->getIsa();
if (fastpath(!cls->hasCustomCore())) {
for (Class tcls = cls; tcls; tcls = tcls->getSuperclass()) {
if (tcls == otherClass) return YES;
}
return NO;
}
#endif
return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}
isKindOfClass
/// 类方法
+ (BOOL)isKindOfClass:(Class)cls {
/// 函数 obj(class) -> isa -> Superclass
for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
/// 对象方法
- (BOOL)isKindOfClass:(Class)cls {
/// 函数 obj(class) -> isa -> Superclass
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
objc_opt_isKindOfClass isKindOfClass看上去没啥区别。实际上上进行了消息的转发。
看下题目的结果
/// NSObject isa rootNSObject superclas NSObject is NSObject =》 1
BOOL kre1 = [[NSObject class] isKindOfClass:[NSObject class]];
/// NSObject isa rootNSObject is NSObject =》 0
BOOL kre2 = [[NSObject class] isMemberOfClass:[NSObject class]];
/// GoodGame isa NSObject superclas nil is GoodGame =》 0
BOOL kre3 = [[GoodGame class] isKindOfClass:[GoodGame class]];
/// GoodGame isa NSObject is GoodGame =》 0
BOOL kre4 = [[GoodGame class] isMemberOfClass:[GoodGame class]];
/// obj(NSObject) isa NSObject is NSObject =》 1
BOOL kre5 = [[NSObject alloc] isKindOfClass:[NSObject class]];
/// obj(NSObject) isa NSObject is NSObject =》 1
BOOL kre6 = [[NSObject alloc] isMemberOfClass:[NSObject class]];
/// obj(GoodGame) isa GoodGame is GoodGame =》 1
BOOL kre7 = [[GoodGame alloc] isKindOfClass:[GoodGame class]];
/// obj(GoodGame) isa GoodGame is GoodGame =》 1
BOOL kre8 = [[GoodGame alloc] isMemberOfClass:[GoodGame class]];
NSLog(@"\n k1 :%hhd\n k2 :%hhd\n k3 :%hhd\n k4 :%hhd\n k5:%hhd\n k6:%hhd\n k7:%hhd\n k8:%hhd\n ",kre1,kre2,kre3,kre4,kre5, kre6, kre7, kre8);}
到此虽然。区别在于 在__OBJC2__时有所区别。
- 获取isa的区别
getIsa()
objc_object::getIsa()
{
if (fastpath(!isTaggedPointer())) return ISA();
\
extern objc_class OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
uintptr_t slot, ptr = (uintptr_t)this;
Class cls;
slot = (ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
cls = objc_tag_classes[slot];
if (slowpath(cls == (Class)&OBJC_CLASS_$___NSUnrecognizedTaggedPointer)) {
slot = (ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
cls = objc_tag_ext_classes[slot];
}
return cls;
}
ISA()
objc_object::ISA(bool authenticated)
{
ASSERT(!isTaggedPointer());
return isa.getDecodedClass(authenticated);
}
isTaggedPointer
是 - 对象的值就是指针
否 - 对象的值是指针指向的内存区域中的值
getIsa 然后调用 ISA()
神头鬼脸,既然一样,为什么搞如此复杂,原来以为发现了新大陆。带着满满的成就感琢磨了半天。研究半天网上一搜,尴了尬。