查看NSObject.mm源码
+ (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;
}
-
isKindOfClass
:是否是同类即子类 -
isMemberOfClass
:是否是同类
两个方法的正确用法:
1.对象方法:
左侧参数的class
对象是否是右侧参数的class
类型
即左侧如果传入instance
对象,右侧参数传入的应该是class
对象.
2.类方法
左侧参数的meta-class
对象是否是右侧参数的meta-class
类型.即左侧如果传入class
对象,右侧应该传入meta-class
对象.
正确用法
LDPerson * person = [[LDPerson alloc] init];
获取instance对象person的class对象,和右侧的class对象比较
NSLog(@"%d",[person isKindOfClass:[NSObject class]]);//1
NSLog(@"%d",[person isMemberOfClass:[NSObject class]]);//0
获取class对象LDPerson的meta-class对象,和右侧的meta-class对象比较
NSLog(@"%d",[LDPerson isKindOfClass:object_getClass([LDPerson class])]);//1
NSLog(@"%d",[LDPerson isMemberOfClass:object_getClass([LDPerson class])]);//1
下面打印结果
NSLog(@"%d",[[NSObject class] isKindOfClass:[NSObject class]]);//1
NSLog(@"%d",[[NSObject class] isMemberOfClass:[NSObject class]]);//0
NSLog(@"%d",[[LDPerson class] isKindOfClass:[LDPerson class]]);//1
NSLog(@"%d",[[LDPerson class] isMemberOfClass:[LDPerson class]]);//0
//等价写法如下
//获取class对象的meta-class ,是否是右侧的meta-class类型
//但是后面都传入的是class对象.使用方法很奇怪,一般不要这样写.
//NSObject的meta-class 不等于NSObject的class对象.然后会通过superclass指针
//拿到NSObject的meta-class的superclass:是NSObject的class对象,所以是1.
NSLog(@"%d",[NSObject isKindOfClass:[NSObject class]]);//1
//NSObject的meta-class 不等于NSObject的class对象
NSLog(@"%d",[NSObject isMemberOfClass:[NSObject class]]);//0
//LDPerson的meta-class 不等于[LDPerson class]//最后找到NSObject,然后是[NSObject class]
NSLog(@"%d",[LDPerson isKindOfClass:[LDPerson class]]);//0
//LDPerson的meta-class 不等于[LDPerson class]
NSLog(@"%d",[LDPerson isMemberOfClass:[LDPerson class]]);//0
打印结果是什么
@interface LDPerson : NSObject
@property (nonatomic,strong) NSString * name;
- (void)print;
@end
@implementation LDPerson
- (void)print{
NSLog(@"%@",self.name);
}
- (void)viewDidLoad {
[super viewDidLoad];
//没有这句代码打印的是控制器
//有这句代码打印的是@"123"
NSString * str = @"123";
id cls = [LDPerson class];
void * obj = &cls;
[(__bridge id)obj print];
}
@end
为什么能调用成功
![](https://img.haomeiwen.com/i1345141/aa7ea7dce6834365.png)
![](https://img.haomeiwen.com/i1345141/ac0610b17a6a0d7d.png)
![](https://img.haomeiwen.com/i1345141/6bd131f643a564ef.png)
-
instcane
对象调用方法是通过instcane
对象的isa
查找到class
对象,然后遍历class
对象的缓存 方法列表 superclass等查找方法.本质是查找class
对象里的方法. -
cls
指向class
对象,相当于instance
对象的isa
指向class
对象.所以obj
相当于instance
对象的指针.cls
相当于instance
对象.cls
的第一个成员就是isa
,所以整合代码:
id obj = cls([[LDPerson alloc] init]);
[obj print];
为什么打印结果是栈空间的第一个成员
LDPerson
的底层结构
struct LDPerson_IMPL{
Class isa;
NSString *_name;
}
所以获取_name
就是忽略前面isa
所占用的八个字节,来取值.obj
当做instance
对象指针使用,obj
指向cls
,cls
即是instance对象内存空间
也是instance对象的isa
.所以取值就是isa
前面分配的内存.就是cls
前面的.
为什么是控制器
[super viewDidLoad]
底层生成代码:
objc_msgSendSuper({
self;
[UIViewController class]
},sel_registerName(""viewDidLoad));
//第一个参数是一个结构体,是一个栈上的局部结构体变量
struct superStruct = {
self;
[UIViewController class]
}
//第二个参数是函数调用.
sel_registerName(""viewDidLoad)
//所以转换后的底层代码为:第一个参数是结构体变量,第二个参数是SEL
objc_msgSendSuper(superStruct,sel_registerName(""viewDidLoad))
所以此时栈结构是:(上面是高地址)
[UIViewController class] |
---|
self |
cls |
obj |
取值是obj
上买八个字节之后的位置,即cls
上面的self.即为控制器对象.
网友评论