有TAnimal
和TCat
两个类,如下代码,请问打印结果是什么?为什么?
@interface TAnimal : NSObject
@end
#import "TAnimal.h"
@implementation TAnimal
@end
@interface TCat : TAnimal
@end
#import "TCat.h"
#import <objc/message.h>
@implementation TCat
- (instancetype)init {
self = [super init]
if (self) {
NSLog(@"==[self class]==%@",NSStringFromClass([self class]));
NSLog(@"==[super class]==%@",NSStringFromClass([super class]));
}
return self;
}
@end
#import <Foundation/Foundation.h>
#import "TAnimal.h"
#import "TCat.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
TCat *c = [[TCat alloc] init];
}
return 0;
}
运行程序,控制台输出:
2020-02-19 11:31:56.116405+0800 LGTest[33763:1022523] ==[self class]==TCat
2020-02-19 11:31:56.117147+0800 LGTest[33763:1022523] ==[super class]==TCat
打印结果竟然都是TCat
,这是为什么呢?
根据class
方法的代码,可知:
- (Class)class {
return object_getClass(self);
}
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
inline Class
objc_object::getIsa()
{
if (!isTaggedPointer()) return ISA();
}
inline Class
objc_object::ISA()
{
return (Class)(isa.bits & ISA_MASK);
}
从代码我们可以知道-class
方法如果传入的实例对象,返回的则是类,由于self
是当前类的实例对象,所以[self class]
的结果是当前类,也就是TCat
。
那么[super class]
的返回是什么呢?
汇编分析
打开汇编,进行分析,可以发现,[super class]
其实调用的是objc_msgSendSuper
,
而其具体方法如下:
objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
struct objc_super {
__unsafe_unretained _Nonnull id receiver;
__unsafe_unretained _Nonnull Class super_class;
};
那么我们可以通过发送消息来进行分析:
struct objc_super cat_super = {
self,
class_getSuperclass([self class])
};
id ms = objc_msgSendSuper(&cat_super, @selector(class));
NSLog(@"===objc_msgSendSuper===%@===", ms);
运行程序,打印结果如下:
image
clang
分析
使用clang
对TCat.m
进行编译,我们可以得到以下结果:
clang -rewrite-objc TCat.m -o TCat.cpp
((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"));
((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("TCat"))}, sel_registerName("class"));
也可以得出,[self class]
其实调用的是objc_msgSend
,参数是self
和sel_registerName("class")
;而[super class]
调用的是objc_msgSendSuper
,参数是
{(id)self, (id)class_getSuperclass(objc_getClass("TCat"))}
和sel_registerName("class")
总结:
-
[self class]
就是发送消息objc_msgSend
,消息接受者self
,方法编号class
-
[super class]
本质就是objc_msgSendSuper
,消息的接收者还是self
,方法编号class
。只是调用objc_msgSendSuper
的时候会直接跳过self
查找,直接在父类中进行查找。
网友评论