消息发送
objc_msgSend流程
未命名 (2).jpg
动态方法解析流程
未命名 (1).jpg
- (void)test1{}
+ (void)test2{}
void c_test(id self, SEL _cmd){}
// - 对象方法的动态解析
+ (BOOL)resolveClassMethod:(SEL)sel{
if (sel == @selector(test)) {
// - 添加test方法, 并将test的方法实现改为test2的方法实现
Method method = class_getInstanceMethod(self, @selector(test1));
class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
// - 2. 添加C语言函数, 并将test的方法实现改为c_test的函数实现
class_addMethod(self, sel, (IMP)c_test, "v16@0:8");
}
return [super resolveClassMethod:sel];
}
// - 实例方法的动态解析
+ (BOOL)resolveInstanceMethod:(SEL)sel{
// - 1. 添加test方法, 并将test的方法实现改为test2的方法实现
if (sel == @selector(test)) {
Method method = class_getClassMethod(object_getClass(self), @selector(test2));
class_addMethod(object_getClass(self), sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
// - 2. 添加C语言函数, 并将test的方法实现改为c_test的函数实现
class_addMethod(self, sel, (IMP)c_test, "v16@0:8");
}
return [super resolveInstanceMethod:sel];
}
消息转发流程
未命名.jpg
-(void)test{}
-(void)test1{}
+(void)test2{}
+(int)test:(int)age height:(float)height{ }
// - 快转发, 让cat去调用test方法
- (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(test)) {
// - 实例方法
return [Cat new];
// - 类方法
return [Cat class]
}
return [super forwardingTargetForSelector:aSelector];
}
// - 慢转发, 让cat去调用test方法
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(test)) {
// - 没有参数的签名
return [NSMethodSignature signatureWithObjCTypes:"v16@0:8"];
}
if (aSelector == @selector(test:height:)) {
// - 有参数的签名
return [NSMethodSignature signatureWithObjCTypes:"i24@0:8i16f20"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
// - 让cat去调用方法
[anInvocation invokeWithTarget:[Cat new]];
// - 让cat去调用另一个方法
anInvocation.target = [Cat new];
anInvocation.selector = @selector(test1);
[anInvocation invoke];
// - 类方法
anInvocation.target = [Cat class];
anInvocation.selector = @selector(test1);
[anInvocation invoke];
// - 带参数的方法
anInvocation.target = [Cat new];
anInvocation.selector = @selector(test1);
int age = 0;
int hei = 0;
[anInvocation getArgument:&age atIndex:2];
[anInvocation getArgument:&hei atIndex:3];
[anInvocation setArgument:&age atIndex:2];
[anInvocation setArgument:&hei atIndex:3];
[anInvocation invoke];
int result = 0;
[anInvocation getReturnValue:&result];
}