objc_msgSend执行流程
本文Demo代码见gitHubDemo
我们先来看看一个小例子
myPerson.h
#import <Foundation/Foundation.h>
@interface myPerson : NSObject
+(void)walk;
-(void)run;
-(void)sayHello:(NSString*)name;
-(NSString*)sayGoodBye:(NSString*)name;
@end
myPerson.m
#import "myPerson.h"
@implementation myPerson
+(void)walk{
NSLog(@"%s",__FUNCTION__);
}
-(void)run{
NSLog(@"%s",__FUNCTION__);
}
-(void)sayHello:(NSString*)name{
NSLog(@"%s--%@",__FUNCTION__,name);
}
-(NSString*)sayGoodBye:(NSString*)name{
return [NSString stringWithFormat:@"%@",name];
}
@end
【main】
#import <Foundation/Foundation.h>
#import "myPerson.h"
#import <objc/runtime.h>
#import <objc/message.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
myPerson *person = [[myPerson alloc]init];
//类方法
[myPerson walk];
((void(*)(id,SEL))objc_msgSend)([myPerson class], @selector(walk));
//实例方法
//没有返回值,没有参数
[person run];
((void(*)(id,SEL))objc_msgSend)(person, @selector(run));
//没有返回值 ,有一个参数
[person sayHello:@"Jack"];
((void(*)(id,SEL,NSString*))objc_msgSend)(person, @selector(sayHello:),@"Lucy");
//有返回值,有一个参数
[person sayGoodBye:@"LaLa"];
NSString *name = ((NSString*(*)(id,SEL,NSString*))objc_msgSend)(person, @selector(sayGoodBye:),@"Kitty");
NSLog(@"%@",name);
}
return 0;
}
打印:
07.objc_msgSend执行流程[15708:14500527] +[myPerson walk]
07.objc_msgSend执行流程[15708:14500527] +[myPerson walk]
07.objc_msgSend执行流程[15708:14500527] -[myPerson run]
07.objc_msgSend执行流程[15708:14500527] -[myPerson run]
07.objc_msgSend执行流程[15708:14500527] -[myPerson sayHello:]--Jack
07.objc_msgSend执行流程[15708:14500527] -[myPerson sayHello:]--Lucy
07.objc_msgSend执行流程[15708:14500527] Kitty
分析:
((void(*)(id,SEL))objc_msgSend)(person, @selector(run));
其中:person为消息接收者(receiver)、run为消息名称
OC的方法调用:消息机制,给方法调用者发送消息
要想实现看底层的具体分析:可参考深入解构objc_msgSend函数的实现
objc_msgSend执行流程
-
OC中的方法调用,其实都是转化为objc_msgSend函数调用
-
objc_msgSend的执行流程分为大致3大阶段
- 消息发送
- 动态方法解析
- 消息转发
-
源码解读(汇编.s文件)
【注:在c语言里面定义的函数名,在汇编里面会前缀一个_】
objc_msgSend消息发送
runtime_11.pngobjc_msgSend动态方法解析
runtime_12.pngobjc_msgSend消息转发
runtime_13.png下面我们根据流程:看看应用
1.动态添加方法
//1
myPerson1.h
#import <Foundation/Foundation.h>
@interface myPerson1 : NSObject
-(void)test;//也可以不写(这样调用的时候,通过objc_msgSend来调用方法)
@end
myPerson1.m
#import "myPerson1.h"
#import <objc/runtime.h>
struct method_t {
SEL sel;
char *types;
IMP imp;
};
@implementation myPerson1
+(BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(test)) {
// 获取其他方法
struct method_t *method = (struct method_t *)class_getInstanceMethod(self, @selector(other));
// 动态添加test方法的实现
class_addMethod(self, sel, method->imp, method->types);
// 返回YES代表有动态添加方法
return YES;
}
return [super resolveInstanceMethod:sel];
}
- (void)other{
NSLog(@"%s", __func__);
}
@end
【main】
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <objc/message.h>
#import "myPerson1.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
myPerson1 *p1 = [[myPerson1 alloc]init];
[p1 test];
//打印:09.动态添加方法[16013:14580544] -[myPerson1 other]
((void(*)(id,SEL))objc_msgSend)(p1, @selector(test));
//打印:09.动态添加方法[16013:14580544] -[myPerson1 other]
}
return 0;
}
补充:
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types){
if (!cls) return NO;
mutex_locker_t lock(runtimeLock);
return ! addMethod(cls, name, imp, types ?: "", NO);
}
=======================================================
//2.
myPerson2.h
#import <Foundation/Foundation.h>
@interface myPerson2 : NSObject
@end
myPerson2.m
#import "myPerson2.h"
#import <objc/runtime.h>
@implementation myPerson2
- (void)other{
NSLog(@"%s", __func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(test)) {
// 获取其他方法
Method method = class_getInstanceMethod(self, @selector(other));
// 动态添加test方法的实现
class_addMethod(self, sel,
method_getImplementation(method),
method_getTypeEncoding(method));
// 返回YES代表有动态添加方法
return YES;
}
return [super resolveInstanceMethod:sel];
}
@end
【main】
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <objc/message.h>
#import "myPerson2.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
myPerson2 *p2 = [[myPerson2 alloc]init];
((void(*)(id,SEL))objc_msgSend)(p2, @selector(test));
}
return 0;
}
打印:09.动态添加方法[16108:14597000] -[myPerson2 other]
======================================================
//3.添加C的方法
myPerosn3.h
#import <Foundation/Foundation.h>
@interface myPerosn3 : NSObject
@end
myPerosn3.m
#import "myPerosn3.h"
#import <objc/runtime.h>
@implementation myPerosn3
void c_other(id self, SEL _cmd){
NSLog(@"c_other - %@ - %@", self, NSStringFromSelector(_cmd));
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(test)) {
// 动态添加test方法的实现
class_addMethod(self, sel, (IMP)c_other, "v16@0:8");
//v:f返回值是void 2个指针16个字节 第一个指针id 类型@ 从0 开始, 第二个 是SEL为 : 从第8个字节开始
// 返回YES代表有动态添加方法
return YES;
}
return [super resolveInstanceMethod:sel];
}
@end
2.消息转发(把消息发给别人)
myPerson.h
#import <Foundation/Foundation.h>
@interface myPerson : NSObject
- (int)test:(int)age;
@end
myPerson.m
#import "myPerson.h"
#import <objc/runtime.h>
#import "myAnimal.h"
@implementation myPerson
//该方法也可以不写
- (id)forwardingTargetForSelector:(SEL)aSelector{
NSLog(@"%s",__FUNCTION__);
if (aSelector == @selector(test:)) {
return nil;
// objc_msgSend([[myAnimal alloc] init], aSelector)
// return [[myAnimal alloc] init]; ////如果 不为nil,则直接不走下面的了,会直接objc_msgSend
}
return [super forwardingTargetForSelector:aSelector];
}
-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{
NSLog(@"%s",__FUNCTION__);
if (aSelector == @selector(test:)) {
// return [NSMethodSignature signatureWithObjCTypes:"i@:I"];
return [[[myAnimal alloc] init] methodSignatureForSelector:aSelector];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
NSLog(@"%s",__FUNCTION__);
// 参数顺序:receiver、selector、other arguments
// int age;
// [anInvocation getArgument:&age atIndex:2];
// NSLog(@"%d", age + 10);
// anInvocation.target == [[myAnimal alloc] init]; //方法调用者
// anInvocation.selector == test; //方法名
// anInvocation的参数:15
// [[[myAnimal alloc] init] test:15];
[anInvocation invokeWithTarget:[[myAnimal alloc] init]];
int ret;
[anInvocation getReturnValue:&ret];
NSLog(@"----%d", ret);
}
@end
myAnimal.h
#import <Foundation/Foundation.h>
@interface myAnimal : NSObject
@end
myAnimal.m
#import "myAnimal.h"
@implementation myAnimal
- (int)test:(int)age{
return age * 2;
}
@end
【main】
#import <Foundation/Foundation.h>
#import "myPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
myPerson *p = [[myPerson alloc]init];
NSLog(@"%d",[p test:10]);
}
return 0;
}
打印:
10.消息转发[16501:14651870] -[myPerson forwardingTargetForSelector:]
10.消息转发[16501:14651870] -[myPerson methodSignatureForSelector:]
10.消息转发[16501:14651870] -[myPerson forwardInvocation:]
10.消息转发[16501:14651870] ----20
10.消息转发[16501:14651870] 20
3.类方法的消息转发
1.
myPerson1.h
#import <Foundation/Foundation.h>
@interface myPerson1 : NSObject
+ (void)test;
@end
myPerson1.m
#import "myPerson1.h"
#import <objc/runtime.h>
#import "myAnimal.h"
@implementation myPerson1
+ (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(test)) return [myAnimal class];
return [super forwardingTargetForSelector:aSelector];
}
@end
======================================
myPerson2.h
#import <Foundation/Foundation.h>
@interface myPerson2 : NSObject
+ (void)test;
@end
myPerson2.m
#import "myPerson2.h"
@implementation myPerson2
+ (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(test)) return nil; //执行下面的methodSignatureForSelector方法
return [super forwardingTargetForSelector:aSelector];
}
+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(test)) return [NSMethodSignature signatureWithObjCTypes:"v@:"];
return [super methodSignatureForSelector:aSelector];
}
+ (void)forwardInvocation:(NSInvocation *)anInvocation{
NSLog(@"1123");
}
@end
=====================================
myPerson3.h
#import <Foundation/Foundation.h>
@interface myPerson3 : NSObject
+ (void)test;
@end
myPerson3.m
#import "myPerson3.h"
#import <objc/runtime.h>
#import "myAnimal.h"
@implementation myPerson3
+ (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(test)) return [[myAnimal alloc] init];//(此时会调用myAnimal的-test方法)
//(本质: objc_msgSend([[MJCat alloc] init], @selector(test)))
return [super forwardingTargetForSelector:aSelector];
}
@end
myAnimal.h
#import <Foundation/Foundation.h>
@interface myAnimal : NSObject
@end
myAnimal.m
#import "myAnimal.h"
@implementation myAnimal
+(void)test{
NSLog(@"%s",__FUNCTION__);
}
- (void)test{
NSLog(@"%s",__FUNCTION__);
}
@end
【main】
#import <Foundation/Foundation.h>
#import "myPerson1.h"
#import "myPerson2.h"
#import "myPerson3.h"
// 元类对象是一种特殊的类对象
int main(int argc, const char * argv[]) {
@autoreleasepool {
[myPerson1 test];
[myPerson2 test];
[myPerson3 test];
}
return 0;
}
打印:
11.类方法的消息转发[19716:14685988] +[myAnimal test]
11.类方法的消息转发[19716:14685988] 1123
11.类方法的消息转发[19716:14685988] -[myAnimal test]
4.@dynamic
myPerson.h
#import <Foundation/Foundation.h>
@interface myPerson : NSObject
@property (assign, nonatomic) int age;
@property (assign, nonatomic) double height;
@end
myPerson.m
#import "myPerson.h"
#import <objc/runtime.h>
/*
说明:写了属性,编译器会自动生成set、get方法,以及 _ 成员变量(@synthesize age = _age, height = _height;)
@synthesize age = abc也可以(生成对应的abc成员变量)
*/
@implementation myPerson
//提醒编译器不要自动生成setter和getter的实现、不要自动生成_成员变量
@dynamic age;
void setAge(id self, SEL _cmd, int age){
NSLog(@"age is %d", age);
}
int age(id self, SEL _cmd){
return 120;
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(setAge:)) {
class_addMethod(self, sel, (IMP)setAge, "v@:I");
return YES;
} else if (sel == @selector(age)) {
class_addMethod(self, sel, (IMP)age, "i@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
//@synthesize age = _age;
//- (void)setAge:(int)age{
// _age = age;
//}
//- (int)age{
// return _age;
//}
@end
【main】
#import <Foundation/Foundation.h>
#import "myPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
myPerson *p = [[myPerson alloc]init];
p.age = 100;
NSLog(@"age = %d",p.age);
}
return 0;
}
打印:
12.dynamic[19912:14736298] age is 100
12.dynamic[19912:14736298] age = 120
友情链接:
网友评论