博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS开发之NSMethodSignature(方法签名)
阅读量:4146 次
发布时间:2019-05-25

本文共 4767 字,大约阅读时间需要 15 分钟。

OC中方法调用有三种:

第一种:直接调用

- (void)viewDidLoad {
[super viewDidLoad]; [self printStr1:@"hello"];}- (void)printStr1:(NSString*)str{
NSLog(@"printStr1 %@",str);}

第二种:通过performSelector

- (void)viewDidLoad {
[super viewDidLoad]; [self performSelector:@selector(printStr1:) withObject:@"hello world"];}- (void)printStr1:(NSString*)str{
NSLog(@"printStr1 %@",str);}

第三种:NSMethodSignature 和NSInvocation

//1.获取方法签名    NSMethodSignature *sigOfPrintStr = [self methodSignatureForSelector:@selector(printStr1:)];        //2.获取方法签名对应的invocation    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sigOfPrintStr];    /**     3.设置消息接受者,与[invocationOfPrintStr setArgument:(__bridge void * _Nonnull)(self) atIndex:0]等价     */    [invocation setTarget:self];        /**4.设置要执行的selector。与[invocationOfPrintStr setArgument:@selector(printStr1:) atIndex:1] 等价*/    [invocation setSelector:@selector(printStr1:)];        //5.设置参数    NSString *str = @"hello world";    [invocation setArgument:&str atIndex:2];    //开始执行    [invocation invoke];

NSMethodSignature概述

NSMethodSignature和NSInvocation是Foundation框架为咱们提供的一种调用方法的方式,常常用于消息转发。
NSMethodSignature用于描述method的类型信息:返回值类型,及每一个参数的类型。 能够经过下面的方式进行建立:

创建方法有三种:

@interface NSObject //获取实例方法的签名 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector; //获取类方法的签名 + (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector; @end
//使用ObjCTypes建立方法签名 @interface NSMethodSignature + (nullable NSMethodSignature *)signatureWithObjCTypes:(const char *)types; @end

其实ObjcTypes就是 “v@😡”。它是一个是字符串数组,该数组包含了方法的类型编码。

比如有下面这样一个方法:

- (void)goToSchoolWithPerson:(Person *)person; [zhangsan goToSchoolWithPerson:lisi];

我们都知道消息发送会被转换成objc _ msgSend(id reciever,SEL sel,prarams1,params2,…)。所以上面的方法会被转换成:

void objc_msgSend(zhangsan,@selector(goToSchoolWithPerson:),lisi);   //包含两个隐藏参数

这里的 “v@😡”就代表:

  1. “v”:代表返回值void
  2. “@”:代表一个对象,这里指代的id类型zhangsan,也就是消息的receiver
  3. “:”:代表SEL
  4. “@”:代表参数lisi

NSMethodSignature的一种应用

数据模型解析中对null数据的处理

#import "NSNull+BCMNull.h"@implementation NSNull (BCMNull)- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];#ifdef DEBUG //抛出错误调用栈信息 NSLog(@"=========NSNull Message=================\n%@", [NSThread callStackSymbols]);#else#endif NSArray *someClass = @[[NSMutableArray class], [NSMutableString class], [NSMutableDictionary class], [NSDate class], [NSNumber class], [NSData class]]; ///> 如果签名方法不存在,则生成一个签名方法 if (!methodSignature) {
for (Class class in someClass) {
if ([class instancesRespondToSelector:aSelector]) {
methodSignature = [class instanceMethodSignatureForSelector:aSelector]; } } } return methodSignature;}- (void)forwardInvocation:(NSInvocation *)anInvocation {
anInvocation.target = nil; [anInvocation invoke];}@end

举例:

建立一个TestModel类,只声明testMethod,而不去实现,如果TestModel对象调用testMethod时会crash。
如果不想crash,就必须实现methodSignatureForSelector和forwardInvocation,在methodSignatureForSelector方法里面返回一个对应的方法签名。

#import "TestModel.h"@implementation TestModel- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if(aSelector == @selector(testMethod)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } return nil;} -(void)forwardInvocation:(NSInvocation *)anInvocation{
}-(void)testMethod2 {
NSLog(@"调用了方法2");}@end

当然你也可以在forwardInvocation方法里面写一些其他内容,

新建一个TestModelHelper1类,声明且实现testMethod方法:

#import "TestModelHelper1.h"@implementation TestModelHelper1-(void)testMethod{
NSLog(@"i am TestModelHelper1");} @end

在forwardInvocation里面增加如下代码:

#import "TestModel.h"#import "TestModelHelper1.h"@implementation TestModel- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if(aSelector == @selector(testMethod)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } return nil;} -(void)forwardInvocation:(NSInvocation *)anInvocation{
if (anInvocation.selector == @selector(testMethod)) {
TestModelHelper1 *h1 = [[TestModelHelper1 alloc] init]; [anInvocation invokeWithTarget:h1]; }}-(void)testMethod2 {
NSLog(@"调用了方法2");}@end

控制台输出:

2021-05-21 13:46:25.716145+0800 TestMethodSignature[12594:313045] i am TestModelHelper1

由此,我们得出方法调用顺序:

向一个实例发送一个消息后,系统是处理的流程:
1.系统会check是否能response这个消息,如果没有,系统就会发出methodSignatureForSelector消息,寻问它这个消息是否有效?有效就返回对应的方法地址之类的,无效则返回nil。如果是nil,Runtime则会发出-doesNotRecognizeSelector:消息,程序这时也就挂掉了. 如果不是nil接着发送forwardInvocation消息。
2.如果能response则调用相应方法。

转载地址:http://cwcti.baihongyu.com/

你可能感兴趣的文章
网络协议——VXLAN 报文格式
查看>>
IPC——管道和 FIFO
查看>>
Linux——进程、线程
查看>>
Pause(Infra)容器
查看>>
ibatis与hibernate的优缺点以及实用性功能比较
查看>>
weblogic中解析xml文件的问题
查看>>
java长连接调用的方式
查看>>
oracle两张表的数据比较
查看>>
java发送email
查看>>
bea weblogic平台下j2ee调优攻略
查看>>
oracle导入导出数据
查看>>
java利用poi读取excel
查看>>
java常看程序员网站
查看>>
必须要理解掌握的贝塞尔曲线
查看>>
服务端渲染和客户端渲染区别?
查看>>
编译与链接详解
查看>>
windows异常处理__try__except
查看>>
performance 查看页面性能
查看>>
STL中vector、list、deque和map的区别
查看>>
WinDbg-如何抓取dump文件
查看>>