iOS开发 方法签名

1. 什么是方法签名?

iOS中的方法签名是通过NSMethodSignature实现的, 包含方法的返回值和参数;下面我们看看NSMethodSignature的常用方法和属性

1.1 NSMethodSignature自己的方法

//手动初始化方法
+ (nullable NSMethodSignature *)signatureWithObjCTypes:(const char *)types;

使用:

NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:"];

signatureWithObjCTypes的参数可查看官方文档的相关介绍

1.2 NSObject中的方法

除了NSMethodSignature类中包含创建NSMethodSignature对象的方法, NSObject中也包含获取NSMethodSignature对象的方法

//1. 获取类方法或者实例方法签名, 无论是对象还是类对象都能调用该方法
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
//2. 只能获取实例方法签名
+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector

值得注意的是, NSObject中的方法, NSObject的子类都可以调用, 所以一般有三种情况

  1. 从类中获取类方法签名
  2. 从类中获取实例方法签名
  3. 从实例中获取实例方法签名
    但是不能从实例中获取类方法签名, 因为类方法是存放在元类中的, 实例只能获取实例对应的类对象中的方法

1.2.1 从类中获取类方法签名实例方法签名

    NSMethodSignature *s1 = [NSString methodSignatureForSelector:@selector(alloc)];
    NSMethodSignature *s2 = [NSString methodSignatureForSelector:@selector(init)];
    NSLog(@"--s1:%@",s1);
    NSLog(@"--s2:%@",s2);

结果:

屏幕快照 2018-08-16 上午9.29.21.png

我们可以发现, 从不同的方法获取到的方法签名, 为什么是一样的?
因为方法虽然不同, 但是方法的签名是一样的(同一个NSMethodSignature), 即方法的返回值类型参数类型是一样的

1.2.2 从实例对象中可获取实例方法签名, 不能获取类方法签名

    NSString *str = @"string...";
    NSMethodSignature *s3 = [str methodSignatureForSelector:@selector(alloc)];
    NSMethodSignature *s4 = [str methodSignatureForSelector:@selector(init)];
    NSLog(@"--s3:%@",s3);
    NSLog(@"--s4:%@",s4);

结果:


屏幕快照 2018-08-16 上午9.48.33.png

1.2.3 instanceMethodSignatureForSelector只能获取实例方法的签名

NSMethodSignature *s5 = [NSString instanceMethodSignatureForSelector:@selector(alloc)];
NSMethodSignature *s6 = [NSString instanceMethodSignatureForSelector:@selector(init)];
NSLog(@"--s5:%@",s5);
NSLog(@"--s6:%@",s6);

结果:


屏幕快照 2018-08-16 上午9.53.12.png


2. 如何使用方法签名

- (void)signatureTest {
    //1. 创建方法签名
    NSMethodSignature *s9 = [NSMethodSignature signatureWithObjCTypes:"v@:ii"];
    //2. 根据方法签名创建一个NSInvocation对象
    NSInvocation *invo = [NSInvocation invocationWithMethodSignature:s9];
    //3. 为NSInvocation对象设置接收消息的对象
    [invo setTarget:self];
    //4. 为NSInvocation对象设置发送的消息
    [invo setSelector:@selector(test11:)];
    //5. 为NSInvocation对象设置一个新的参数
    NSInteger a = 1;
    [invo setArgument:&a atIndex:2];
    //6. 调用NSInvocation
    [invo invoke];
}

- (void)test11:(int )a{
    NSLog(@"-----:%d",a);
}

结果:

2018-08-16 11:19:39.493722+0800 RuntimeNew[4527:236471] -----:1

解释:

  1. 我们一开始创建的方法签名是有4个参数 @ : i i, 除了前两个是每个方法都有的, 我们又添加了两个int类型的参数, 但是我们的方法- (void)test11:(int )a中并只有一个参数, 依然可以执行, 说明签名函数的参数数量大于被调用的函数参数数量时, 也是可以正常调用的.


3.2 在Runtime的方法转发机制使用

- (void)viewDidLoad {
    [super viewDidLoad];
    [self performSelector:@selector(testMethod:)];
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    return YES;//返回YES,进入下一步转发
}

- (id)forwardingTargetForSelector:(SEL)aSelector {
    return nil;//返回nil,进入下一步转发
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if ([NSStringFromSelector(aSelector) isEqualToString:@"testMethod:"]) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    SEL sel = anInvocation.selector;
    Person *p = [Person new];
    if([p respondsToSelector:sel]) {
        NSString *str = @"Lucy";
        [anInvocation setArgument:&str atIndex:2];
        [anInvocation invokeWithTarget:p];
    }
    else {
        [self doesNotRecognizeSelector:sel];
    }
}
  1. 我们希望self执行testMethod, 但是self并没有实现该方法, 所以我们要一步一步去找
  2. resolveInstanceMethod:返回YES, 意味着我们没有为testMethod添加函数实现, 执行下一步forwardingTargetForSelector
  3. forwardingTargetForSelector返回nil, 意味着我们没有为该方法提供备用接收者, 所以只能继续执行下一步, 通过方法签名和NSInvocation来实现完整的消息转发
  4. methodSignatureForSelector拿到方法签名---在forwardInvocation指定一个对象, 判断该对象是否实现了此方法. 实现了, 则执行; 未实现, 则调用doesNotRecognizeSelector方法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269