0%

理解objc_msgSend的作用

理解objc_msgSend的作用

1
objc_msgSend(void /* id self, SEL op, ... */ )

是一个参数可变的函数,能接受两个或者两个以上的参数,会根据依次的接受者与选择器的类型来调用适当的方法,为了完成此操作,该方法需要在接受者所属的类中寻找其 方法列表,如果找到与选择器相同的方法就调至其实现代码,若找不到沿着继承体系向上查找,等找到合适的方法之后在跳转,如果最终找不到,就执行消息转发;

objc_msgSend函数举例

被调方法类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// GCMsgSend.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

struct myStructTest {
char *name;
int age;
};

@interface GCMsgSend : NSObject

- (void)noArgumentAndNoReturnValue;

- (void)hasArguments:(NSString *)arg;

- (NSString *)noArgumentsButRetuenValue;

- (int)hasArguments:(NSString *)arg andReturnValue:(int)arg1;

int cStyleFunc(const void *arg1, const void *arg2);

- (float)noArgumentAndReturnFloatValue;

- (struct myStructTest)returnStructValue;

@end


@interface GCMsgSendClass: GCMsgSend

- (void)getSuperClass;

@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// GCMsgSend.m
#import "GCMsgSend.h"

@implementation GCMsgSend

- (void)noArgumentAndNoReturnValue {
NSLog(@"%s was called, and it has no arguments and return value", __FUNCTION__);
}

- (void)hasArguments:(NSString *)arg {
NSLog(@"%s was called, and arguments is %@", __FUNCTION__, arg);
}

- (NSString *)noArgumentsButRetuenValue {
NSLog(@"%s was called, and return value is %@", __FUNCTION__, @"不带参数,但是有返回值");
return @"不带参数,但是有返回值";
}

- (int)hasArguments:(NSString *)arg andReturnValue:(int)arg1 {
NSLog(@"%s was called, and argument is %@, retuen value is %d", __FUNCTION__, arg, arg1);
return arg1;
}

//声明一个C函数
int cStyleFunc(const void *arg1, const void *arg2) {
NSLog(@"%s was called, arg1 is %s, and age2 is %s", __FUNCTION__, arg1, arg2);
return 1;
}

- (float)noArgumentAndReturnFloatValue {
NSLog(@"%s was called, 带浮点数的返回值", __FUNCTION__);
return 10.24;
}

- (struct myStructTest)returnStructValue {
struct myStructTest test = {
"Ghost",
1024,
};
return test;
}
@end


@implementation GCMsgSendClass

- (void)getSuperClass {

}

@end

掉用类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#import "GCMsgSend.h"
#import <objc/message.h>

- (void)msgTest {
//创建对象
GCMsgSend *msg = ( (GCMsgSend * (*)(id, SEL)) objc_msgSend) ((id)[GCMsgSend class],@selector(alloc));

//初始化对象
msg = ((GCMsgSend *(*)(id, SEL))objc_msgSend) ((id)msg, @selector(init));

//调用无参无返回值的方法
((void (*)(id, SEL))objc_msgSend)((id)msg, @selector(noArgumentAndNoReturnValue));

//带参数不带无返回值
((void(*)(id, SEL, NSString *))objc_msgSend)((id)msg, @selector(hasArguments:), @"一个参数,无返回值");

//不带参数有返回值
NSString *retValue = ((NSString *(*)(id, SEL))objc_msgSend)((id)msg, @selector(noArgumentsButRetuenValue));
NSLog(@"返回值是: %@", retValue);

//带参数带返回值
int returnValue = ((int (*)(id, SEL, NSString *, int))objc_msgSend)((id)msg, @selector(hasArguments:andReturnValue:), @"参数1", 2018);
NSLog(@"返回值是: %d", returnValue);

//动态添加方法再调用
class_addMethod(msg.class, NSSelectorFromString(@"cStyleFunc"), (IMP)cStyleFunc, "v@:");
returnValue = ((int(*)(id, SEL, const void *, const void *))objc_msgSend)((id)msg, NSSelectorFromString(@"cStyleFunc"), "参数1", "参数2");
NSLog(@"返回值是: %d", returnValue);

//带浮点返回值
float returnFloatValue = ((float(*)(id, SEL))objc_msgSend)((id)msg, @selector(noArgumentAndReturnFloatValue));
NSLog(@"浮点数返回值是: %f", returnFloatValue);

//带结构体的返回值 objc_msgSend_stret 已经废弃
struct myStructTest structValue = ((struct myStructTest(*)(id, SEL))objc_msgSend)((id)msg, @selector(returnStructValue));
NSLog(@"结构体返回: name = %s, age = %d", structValue.name, structValue.age);

//给父类发送消息
//初始化子类
GCMsgSendClass *msgClass = ((GCMsgSendClass *(*)(id, SEL))objc_msgSend)((id)[GCMsgSendClass class], @selector(alloc));
msgClass = ((GCMsgSendClass *(*)(id, SEL))objc_msgSend)((id)msgClass, @selector(init));
//给父类的方法发送消息 掉用objc_msgSendSuper 会Crash
((void(*)(id, SEL, NSString *))objc_msgSend)((id)msgClass, @selector(hasArguments:), @"子类调用父类的方法");
}