一、准备工作
- objc4可编译源码,可直接跳到文章最后,下载调试好的源码
- isa走位图,继承关系图
二、查看源码分析流程
2.1 isKindOfClass
源码
//: 实例方法
- (BOOL)isKindOfClass:(Class)cls {
//: 1、拿到调用者`self`的类,判断是否和cls相等
//: 2、相等返回YES,不相等,则再去找`self`的类的父类,递归下去,直到nil跳出循环
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
//: 类方法
+ (BOOL)isKindOfClass:(Class)cls {
//: 1、拿到调用者`self`的元类,判断是否和cls相等
//: 2、相等返回YES,不相等,则再去找`self`的元类的父类,递归下去,直到nil跳出循环
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
isKindOfClass
的实例方法
是拿self
的类
去和cls
做比较,相等则返回YES,不相等则再递归找父类
是否与cls
相等,直到找到nil,跳出循环返回NOisKindOfClass
的类方法
是拿self
的元类
去和cls
做比较,相等则返回YES,不相等则再递归找元类的父类
是否与cls
相等,直到找到nil,跳出循环返回NO
举例:
//: 调用isKindOfClass实例方法
BOOL re1 = [[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL re2 = [[GomuPerson alloc] isKindOfClass:[GomuPerson class]];
BOOL re3 = [[GomuPerson alloc] isKindOfClass:[NSObject class]];
//: 调用isKindOfClass类方法
BOOL re4 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL re5 = [[GomuPerson class] isKindOfClass:[GomuPerson class]];
BOOL re6 = [[GomuPerson class] isKindOfClass:[NSObject class]];
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n re5 :%hhd\n re6 :%hhd\n",re1,re2,re3,re4,re5,re6);
//: 打印
re1 :1
re2 :1
re3 :1
re4 :1
re5 :0
re6 :1
2.1.1 [[NSObject alloc] isKindOfClass:[NSObject class]]
流程
- 拿到
[NSObject alloc]
的class
=NSObject
- 传入的
cls
=[NSObject class]
=NSObject
-
NSObject
=NSObject
,返回YES
2.1.2 [[GomuPerson alloc] isKindOfClass:[GomuPerson class]]
流程
- 拿到
[GomuPerson alloc]
的class
=GomuPerson
- 传入的
cls
=[GomuPerson class]
=GomuPerson
-
GomuPerson
=GomuPerson
,返回YES
2.1.3 [[GomuPerson alloc] isKindOfClass:[NSObject class]]
流程
- 拿到
[GomuPerson alloc]
的class
=GomuPerson
- 传入的
cls
=[NSObject class]
=NSObject
-
GomuPerson
!=NSObject
,递归找GomuPerson
的父类 -
GomuPerson
的父类 =NSObject
-
NSObject
=NSObject
,返回YES
2.1.4 [[NSObject class] isKindOfClass:[NSObject class]]
流程
- 拿到
[NSObject class]
的元类 =NSObject元类,即根元类
- 传入的
cls
=[NSObject class]
=NSObject
-
NSObject元类
!=NSObject
,递归找根元类
的父类 -
根元类
的父类 =NSObject
-
NSObject
=NSObject
,返回YES
2.1.5 [[GomuPerson class] isKindOfClass:[GomuPerson class]]
流程
- 拿到
[GomuPerson class]
的元类 =GomuPerson元类
- 传入的
cls
=[GomuPerson class]
=GomuPerson
-
GomuPerson元类
!=GomuPerson
,递归找GomuPerson元类
的父类 -
GomuPerson元类
的父类 =根元类
-
根元类
!=GomuPerson
,递归找根元类
的父类 -
根元类
的父类 =NSObject
-
NSObject
!=GomuPerson
,递归找NSObject
的父类 -
NSObject
的父类 =nil
-
nil
!=GomuPerson
,跳出循环,返回NO
2.1.6 [[GomuPerson class] isKindOfClass:[NSObject class]]
流程
- 拿到
[GomuPerson class]
的元类 =GomuPerson元类
- 传入的
cls
=[NSObject class]
=NSObject
-
GomuPerson元类
!=NSObject
,递归找GomuPerson元类
的父类 -
GomuPerson元类
的父类 =根元类
-
根元类
!=NSObject
,递归找根元类
的父类 -
根元类
的父类 =NSObject
-
NSObject
=NSObject
,返回YES
2.1.7 流程图
isKindOfClass流程图.png2.1.8 总结
isKindOfClass
实例方法和类方法的区别在于,实例方法
是拿对象的类
去和cls
比较,再进行递归找对象的类
的父类进行比较,类方法
则是拿类的元类
去和cls
比较,再进行递归找类的元类
的父类进行比较isKindOfClass
实例方法中,即是判断当前调用方法的对象所属类
是否继承cls
或者与cls
是同一个类
isKindOfClass
类方法中,即是判断当前调用方法的类所属元类
是否继承cls
或者与cls
是同一个类
类
是元类
的对象
,那么isKindOfClass
就很好理解了,不用区分是否是类/实例
方法,他的作用就是判断当前对象(类对象)
是否继承cls
/与cls是同一个类
2.2 isMemberOfClass
源码
//: 实例方法
- (BOOL)isMemberOfClass:(Class)cls {
//: 拿到调用者`self`的类,判断是否和cls相等
return [self class] == cls;
}
//: 类方法
+ (BOOL)isMemberOfClass:(Class)cls {
//: 拿到调用者`self`的类的元类,判断是否和cls相等
return self->ISA() == cls;
}
isMemberOfClass
的实例方法
是拿self
的类,判断是否和cls相等isMemberOfClass
的类方法
是拿self
的类的元类,判断是否和cls相等
举例:
//: 调用isMemberOfClass实例方法
BOOL re1 = [[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL re2 = [[GomuPerson alloc] isMemberOfClass:[GomuPerson class]];
BOOL re3 = [[GomuPerson alloc] isMemberOfClass:[NSObject class]];
//: 调用isMemberOfClass类方法
BOOL re4 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL re5 = [[GomuPerson class] isMemberOfClass:[GomuPerson class]];
BOOL re6 = [[GomuPerson class] isMemberOfClass:[NSObject class]];
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n re5 :%hhd\n re6 :%hhd\n",re1,re2,re3,re4,re5,re6);
//: 打印
re1 :1
re2 :1
re3 :0
re4 :0
re5 :0
re6 :0
2.2.1 [[NSObject alloc] isMemberOfClass:[NSObject class]]流程
- 拿到
[NSObject alloc]
的class
=NSObject
- 传入的
cls
=[NSObject class]
=NSObject
-
NSObject
=NSObject
,返回YES
2.2.2 [[GomuPerson alloc] isMemberOfClass:[GomuPerson class]]流程
- 拿到
[GomuPerson alloc]
的class
=GomuPerson
- 传入的
cls
=[GomuPerson class]
=GomuPerson
-
GomuPerson
=GomuPerson
,返回YES
2.2.3 [[GomuPerson alloc] isMemberOfClass:[NSObject class]]流程
- 拿到
[GomuPerson alloc]
的class
=GomuPerson
- 传入的
cls
=[GomuPerson class]
=NSObject
-
GomuPerson
!=NSObject
,返回NO
2.2.4 [[NSObject class] isMemberOfClass:[NSObject class]]流程
- 拿到
[NSObject class]
的元类
=NSObject 元类
- 传入的
cls
=[NSObject class]
=NSObject
-
NSObject 元类
!=NSObject
,返回NO
2.2.5 [[GomuPerson class] isMemberOfClass:[GomuPerson class]]流程
- 拿到
[GomuPerson class]
的元类
=GomuPerson 元类
- 传入的
cls
=[GomuPerson class]
=GomuPerson
-
GomuPerson 元类
!=GomuPerson
,返回NO
2.2.6 [[GomuPerson class] isMemberOfClass:[NSObject class]]流程
- 拿到
[GomuPerson class]
的元类
=GomuPerson 元类
- 传入的
cls
=[NSObject class]
=NSObject
-
GomuPerson 元类
!=NSObject
,返回NO
2.2.7 流程图
isMemberOfClass流程图.png2.2.8 总结
isMemberOfClass
实例方法中,即是判断当前调用方法的对象所属类
是否与cls
是同一个类
isMemberOfClass
类方法中,即是判断当前调用方法的类所属元类
是否与cls
是同一个类
类
是元类
的对象
,那么isMemberOfClass
就很好理解了,不用区分是否是类/实例
方法,他的作用就是判断当前对象(类对象)
是否与cls是同一个类
三、总结
3.1 isKindOfClass
的作用
判断
对象所属类
/类对象所属元类
是否继承cls
/与cls相等
3.2 isMemberOfClass
的作用
判断
对象所属类
/类对象所属元类
是否与cls相等
四、补充说明
//: 经过断点调试,这两方法都不会走
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); 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;
}
//: 都会调用一个相同的方法
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
if (slowpath(!obj)) return NO;
Class cls = obj->getIsa();
if (fastpath(!cls->hasCustomCore())) {
for (Class tcls = cls; tcls; tcls = tcls->superclass) {
if (tcls == otherClass) return YES;
}
return NO;
}
#endif
return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}
//: getIsa() 方法
inline Class
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()方法
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
}
-
objc_opt_isKindOfClass
会调用obj->getIsa()
-
obj->getIsa()
会调用ISA()
- 进入
ISA()
,会返回(Class)(isa.bits & ISA_MASK)
-
(Class)(isa.bits & ISA_MASK)
就是把isa转成类 - 所以当
obj
是实例对象的时候,obj->getIsa()
等同于 [obj class],拿到对象的类。 - 当
obj
是对象的时候,obj->getIsa()
就是拿类的元类。
isKindOfClass
的实例方法和类方法都调同一个方法是没有问题的,逻辑是通的
网友评论