OC中的方法调用,其实都是转换为objc_msgSend函数的调用
objc_msgSend的执行流程可以分为3大阶段
- 1.消息发送
- 2.动态方法解析
- 3.消息转发
1.消息发送
流程如下:
备注:
- 在class_rw_t查找方法时,如果已经排序的,则二分查找提高效率, 如果没有排序的,遍历查找
- receiver通过isa指针找到receiverClass
- receiverClass通过superclass指针找到superClass
2.动态方法解析
流程如下- 动态解析过后,会重新走“消息发送”的流程“从receiverClass的cache中查找方法”这一步开始执行
示例
+resolveInstanceMethod:
+resolveClassMethod:
在上述两个方法中防止崩溃
@interface ClassA : NSObject
- (void)test;
@end
#import "ClassA.h"
#import <objc/runtime.h>
@implementation ClassA
- (void)other {
NSLog(@"在.m里没有实现test方法 正常情况下会报错, 但是在resolveInstanceMethod进行了处理就不会有问题了");
}
// 没找到对象方法的时候调用这个
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(logAAA)) {
// 创建一个方法
Method otherMethod = class_getInstanceMethod(self, @selector(other));
class_addMethod(self, sel,
// 之前定义方法的实现
method_getImplementation(otherMethod),
// types
method_getTypeEncoding(otherMethod));
return YES;
}
return [super resolveInstanceMethod:sel];
}
@end
3.消息转发阶段
当实现过 2动态方法解析阶段, 会进入消息转发阶段
相关代码
- (id)forwardingTargetForSelector:(SEL)aSelector {
return [super forwardingTargetForSelector:aSelector];
}
// 返回方法签名: 返回值类型, 参数类型
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(test)) {
return [NSMethodSignature signatureWithObjCTypes:@"v20@0:i16"];
}
return [super methodSignatureForSelector:aSelector];
}
// NSInvocation 封装了一个方法调动, 包括 方法调用者, 方法名, 方法参数
// anInvocation.selector 方法名
// anInvocation.target 方法调用者
- (void)forwardInvocation:(NSInvocation *)anInvocation {
// 在这里修改 target 和selecor 从而实现消息发送
anInvocation.target = [[ClassC alloc]init];
anInvocation.selector = @selector(classCTest);
[aninvocation invoke];
}
注意: 类方法的 消息转发阶段 全都是+方法
[self class] 和[super class]
1:底层实现
// self
objc_msgSend
// super
objc_msgSendSuper(self, @selector(class))
2:self和super的消息接收者都是当前类 例如, [self class]和 [super class] 消息接收者都是self 但是查找层级不同 self 从当前类查找, super 从父类查找
3: class 方法虽然每个oc对象都有声明, 但是具体实现是在NSObject里面
NSObject中class的实现 大体是
- (Class)class
{
return object_getClass(self);
}
- (Class)superClass
{
return object_getSuperclass(self);
}
结论: 由源码可以看出 class和superClass 的消息接收者都是self
迁移
@interface Person : NSObject
@end
@interface Student : Person
@end
@implementation Student
- (instancetype)init
{
self = [super init];
if (self) {
NSLog(@"%@", [self class]); Student
NSLog(@"%@", [self superclass]); Person
NSLog(@"%@", [super class]); Student
NSLog(@"%@", [super superclass]); Person
}
return self;
}
@end