编码篇 - NSInvocation的简单使用

前言

在认识 NSInvocation 之前,iOS开发中我们一般会使用以下两种方式去调用一个方法

(1) [obj methodName]; 
(2) [obj performSelector......];

但是我们知道,这两种方式都有各自的缺陷: 第一种的方法:无法通过方法名字符串来调用方法; 第二种方式:不能执行参数过多的方法,一般参数数量不能超过2个就很麻烦处理了。

那么有没有一种方式,既可以通过方法名字符串来调用方法,也可以传递很多参数呢?答案肯定是有的,那就是 NSInvocation 。NSInvocation可以处理很多参数、返回值。会java的人都知道反射操作,其实NSInvocation就相当于反射操作。

NSInvocation

文档描述

An NSInvocation is an Objective-C message rendered static, that is, it is an action turned into an object. NSInvocation objects are used to store and forward messages between objects and between applications, primarily by NSTimer objects and the distributed objects system.

NSInvocation可以去构建一个方法然后转发这个方法,所以我们可以利用这两点特性去做一些事情。

常见方法及属性

NSInvocation其他常见方法属性

 //保留参数,它会将传入的所有参数以及target都retain一遍
- (void)retainArguments
// 判断参数是否存在,调用retainArguments之前,值为NO,调用之后值为YES
 @property (readonly) BOOL argumentsRetained;
 // 设置消息返回值
- (void)setReturnValue:(void *)retLoc;

NSMethodSignature其他常见方法属性

 // 方法参数个数
@property (readonly) NSUInteger numberOfArguments;
// 获取方法的长度
@property (readonly) NSUInteger frameLength;
// 是否是单向
- (BOOL)isOneway;
// 获取方法返回值类型
@property (readonly) const char *methodReturnType NS_RETURNS_INNER_POINTER;
// 获取方法返回值的长度
@property (readonly) NSUInteger methodReturnLength;

NSInvocation的使用步骤

(1).指定一个 SEL (2).根据这个 SEL 创建 NSMethodSignature (3).根据这个 NSInvocation 创建一个NSInvocation对象 (4).设置这个 invocation 的 target、selector、参数 、返回值 (5).调用NSInvocation对象的invoke方法

下面是一个具体的使用实例:

NSString *methodNameStr = @"test:withArg2:";
SEL selector = NSSelectorFromString(methodNameStr);
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
//此时我们应该判断方法是否存在,如果不存在这抛出异常
if (signature == nil) {
    //aSelector为传进来的方法
    NSString *info = [NSString stringWithFormat:@"%@方法找不到", NSStringFromSelector(selector)];
    [NSException raise:@"方法调用出现异常" format:info, nil];
}
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = selector;

NSString *arg1 = @"arg1";
NSString *arg2 = @"arg2";
[invocation setArgument:&arg1 atIndex:2];
[invocation setArgument:&arg2 atIndex:3];
[invocation invoke];

if (signature.methodReturnLength>0) {
    id returnResult = nil;
    [invocation getReturnValue:&returnResult];
    NSLog(@"%@",returnResult);
}

- (NSString *)test:(NSString *)ceshiStr withArg2:(NSString *)arg2
{
    NSLog(@"%@----%@",ceshiStr,arg2);
    return @"返回值";
}

PS:如果想根据参数数组,动态设置参数

// invocation 有2个隐藏参数,所以 argument 从2开始
if ([arguments isKindOfClass:[NSArray class]]) {
    NSInteger count = MIN(arguments.count, signature.numberOfArguments - 2);
    for (int i = 0; i < count; i++) {
        const char *type = [signature getArgumentTypeAtIndex:2 + i];
        // 需要做参数类型判断然后解析成对应类型,这里默认所有参数均为OC对象
        if (strcmp(type, "@") == 0) {
            id argument = arguments[i];
            [invocation setArgument:&argument atIndex:2 + i];
        }
    }
}

页面强制旋转中用到的 NSInvocation

  if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
        SEL selector = NSSelectorFromString(@"setOrientation:");
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
        [invocation setSelector:selector];
        [invocation setTarget:[UIDevice currentDevice]];
        int val = UIInterfaceOrientationLandscapeRight;
        [invocation setArgument:&val atIndex:2];
        [invocation invoke];
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏BY的专栏

Objective-C Runtime 的一些基本使用

37880
来自专栏ios 技术积累

ios ARC中如何判断一个对象释放了

NSHashTable效仿了NSSet(NSMutableSet),但提供了比NSSet更多的操作选项,尤其是在对弱引用关系的支持上,NSHashTable在对...

37520
来自专栏前端那些事

递归函数-汉诺塔经典递归

前言 最近在读《JavaScript语言精粹》,对递归函数有了进一步的认识,希望总结下来: 递归是一种强大的编程技术,他把一个问题分解为一组相似的子问题,每一问...

40370
来自专栏DannyHoo的专栏

iOS开发中上传JSON字符串到后台服务器

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

40510
来自专栏编程之旅

iOS开发——正则表达式验证手机号、密码

App的实际应用中,用户登陆功能基本是每个App都有需求的一个功能。而当前我们很常规的做法,就是让用户把手机号作为自己的用户名,而在注册获取短信验证码的过程中,...

66720
来自专栏菩提树下的杨过

objective-C中的Class(类类型),Selector(选择器SEL),函数指针(IMP)

今天在园子里看到了一篇牛文“Objective-C 2.0 with Cocoa Foundation--- 5,Class类型,选择器Selector以及函数...

25650
来自专栏Scott_Mr 个人专栏

利用Runtime实现简单的字典转模型

12930
来自专栏Scott_Mr 个人专栏

利用Runtime实现简单的字典转模型

40860
来自专栏ShaoYL

IOS开发系列—Objective-C之Foundation框架

23460
来自专栏码生

ios 获取属性的类型

19820

扫码关注云+社区

领取腾讯云代金券