isKindOfClass:和isMemberOfClass的用
2018-09-29 本文已影响0人
Gxdy
本文将从NSObject源码的角度来讲述isKindOfClass
和isKindOfClass
使用.
如需要查看更多更新源码资源请前往苹果官方源码下载
isa与superclass.png在进入正文之前先附上一张isa与superclass指针的指向结构图
- isKindOfClass:
(实例方法)
- NSObject源码实现如下
- (BOOL)isKindOfClass:(Class)cls {
// 循环遍历直到匹配到对应class或者tcls==nil
// (从上图可以知道tcls->superclass最终会指向nil)
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
-
分析:从源码可以知道
- isKindOfClass: 实例对象方法
会先通过isa
找到调用者(实例对象)的类对象
进行判断。如果tcls == cls
,就结束遍历返回YES。如果tcls != cls
,就会沿着superclass
指向的方向寻找父类的类对象
,直到条件成立或者tcls=nil。 -
结论:通过
实例对象
访问- isKindOfClass:
方法,判断的是实例对象
的类对象
或者父类的类对象
是否等于cls(传入的参数)
-
如:
UIView *view = [[UIView alloc] init];
[view isKindOfClass: [UIView class]]; // --> YSE
[view isKindOfClass: [NSObject class]]; // --> YSE
+ isKindOfClass:
(类对象方法)
- NSObject源码实现如下
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
-
分析:
- 首先,源码中
tcls
初始 值是object_getClass((id)self)
,这是一个元类对象
。 - 之后
tcls = tcls->superclass
,任然是一个元类对象,之后又成NSObject的类对象
,最后是nil(从上图可知元类对象
的superclass --> SuperClass的元类对象 --> RootClass的元类对象 --> NSObject的类对象 --> nil)。
- 首先,源码中
-
结论:通过实例对象访问
+ isKindOfClass:
方法,判断的是类对象
的元类对象
或者父类的元类对象
或者NSObject的类对象
是否等于cls(传入的参数) -
如:
[UILabel isKindOfClass: [UILabel class]]; // --> NO,元类对象 != [UILabel class](类对象)
[UILabel isKindOfClass: object_getClass([UILabel class])]; // --> YSE
[[UILabel class] isKindOfClass: object_getClass([UILabel class])]; // --> YSE
[[UILabel class] isKindOfClass: object_getClass([UIView class])]; // --> YSE
[[UILabel class] isKindOfClass: object_getClass([NSObject class])]; // --> YSE
[[UILabel class] isKindOfClass: [NSObject class]]; // --> YSE
- isMemberOfClass:
(实例方法)
- NSObject源码实现如下
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
- 源码可知:判断的是
类对象
是否等于cls
- 如:
[[UILabel new] isMemberOfClass:[UILabel class]]; // YES
[[UILabel new] isMemberOfClass:[UIView class]]; // NO
+ isMemberOfClass:
(类对象方法)
- NSObject源码实现如下
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
- 源码可知:判断的是
类对象
的元类对象
是否等于cls
- 如:
[UILabel isMemberOfClass:[UIView class]]; // NO
[UILabel isMemberOfClass:object_getClass([UILabel class])]; // YES
- 总结
- 不管是
isKindOfClass
还是isMemberOfClass
- 在
类对象
调用时,都是与调用者的元类对象
与传入参数
进行判断; - 在
实例对象
调用时,不管是isKindOfClass
还是isMemberOfClass
,都是与调用者的类对象
与传入参数
进行判断;
-
isKindOfClass
具有继承关系,会沿着superclass遍历;isMemberOfClass
,则没有继承关系,只会判断一次
3.注意点与用法:
- 要注意
类对象
调用时,判断的是元类对象
- 要注意
[NSObject class]
在+ isKindOfClass
中的特殊性 - 要注意
isKindOfClass
是有继承关系 - 判断某个对象是什么类(
忽略继承
)时,尽量用isMemberOfClass
- 判断某个对象是继承自什么类(
包含继承
)时,用isKindOfClass