objc_msgSend
OC中的方法调用,其实都是转换为objc_msgSend函数调用
objc_msgSend的执行流程可以分3大阶段
- 消息发送
- 动态方法解析
- 消息转发
objc_msgSend(消息接收者,消息名称)
// 比如:
Person *person = [Person alloc]init];
[person test];
====>objc_msgSend(person,sel_registerName('test'))
// 备注:sel_registerName('test') 与 @selector(test) 作用都是一样的,获取方法名称
//OC的方法调用:消息机制,给方法调用者发送消息
objc_msgSend如果找不到合适的方法进行调用,会报`unrecognized selector sent to instance`
![](https://img.haomeiwen.com/i1923392/a9f6f2b904190869.png)
![](https://img.haomeiwen.com/i1923392/ab67bb202a6130eb.png)
![](https://img.haomeiwen.com/i1923392/af05f2bc4f6e19b0.png)
Super 方法
// 结构体
struct objc_super {
id receiver, // 消息接收者
Class super_class, // 消息接收者的父类(super的作用:从父类的类对象或者父类的元类对象开始找方法)
}
struct objc_super arg = {
self,
class_getSuperclass(objc_getClass(类名))
}
objc_msgSendSuper(arg,@selector(方法名))
#结论:
[super message]的底层实现
1、消息接收者仍然是子类对象
2、从父类开始查找方法的实现
补充:
@synthesize
添加属性的时候时候,在实现文件中,是有这个定义的(默认不显示)
作用就是实现getter和setter方法的实现
比如:@synthesize age = _age;
就是说对age属性生成一个_age成员变量,并且生成getter方法和setter方法的实现
@dynamic
而@dynamic age;
表示:提醒编译器不要自动生成setter方法和getter的实现,不要自动生成成员变量
但是并不影响getter方法和setter方法的声明
面试题:
打印结果分别是什么?
#第一道题:
@interface MJStudent :MJPerson
@end
@interface MJPerson:NSObject
@end
@implementation MJStudent
- (instancetype)init {
if(self = [super init]){
NSLog(@"%@",[self class]); // 打印结果:MJStudent
NSLog(@"%@",[super class]); // 打印结果:MJStudent
NSLog(@"%@",[self superclass]); // 打印结果:MJPerson
NSLog(@"%@",[super superclass]); // 打印结果: MJPerson
}
}
@end
#解析:
[self class]
// 编译后:objc_msgSend(self,@selector(class));
[super class]
// 编译后:objc_msgSendSuper(_objc_super){self,class_getSuperClass(objc_getClass('MJStudent')),@selector(class)};
编译后super与一般的消息机制有点不一样,不过两者都带有一个消息接收者(receiver)self,都是MJStudent对象。
第二,对象方法class,其实现都是在基类NSObject中,而class对象的方法底层实现是
- (Class)class {
// objc_getClass(id)
// 传入的是实例对象,返回的是“类对象”
// 传入的是类对象,返回的是“元类对象”
return object_getClass(self);
}
[self class]和[super class]两个的消息接收者self都是MJStudent,所以返回的结果是MJStudent
superClass 编译后是
- (Class)superclass {
return class_getSuperclass(object_getClass(self))
}
#第二道题
BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [[MJPerson class] isKindOfClass:[MJPerson class]];
BOOL res4 = [[MJPerson class] isMemberOfClass:[MJPerson class]];
NSLog(@"%d %d %d %d",res1,res2,res3,res4);
// 打印结果:1 0 0 0
# 解析
isKindOfClass源码
+ (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;
}
isMemberOfClass源码
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
源码中:
+ isMemberOfClass 和 + isKindOfClass 都是对比消息调用者receiver的“元类”与形参是否相同(要区分“元类”和“类对象”是不一样的),而+isKindOfClass还会通过superclass遍历其父类对比
- isMemberOfClass 和 - isKindOfClass 都是对比消息调用者receiver的“类对象”与形参是否相同,不过-isKindOfClass还会通过superclass遍历其父类对比
BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
消息调用者是“类对象”,形参也是一个“类对象”,编译后就是调用者的“元类”与“类对象”相比,
对比结果肯定是不一样的,但是+isKindOfClass会遍历其superclass再遍历对比,
而[NSObject class]元类的superclass指向的是NSObject的类对象,所以最后是两个NSObject类对象相比,结果是一样的
其余的三道题编译后都是“元类”与“类对象”相比,所以结果都是否(0)
【特殊的一点:基类NSObject元类对象的superClass是指向基类NSObject的类对象】
![](https://img.haomeiwen.com/i1923392/ddc083289a82d1a3.png)
网友评论