iOS 反射函数: performSelector, NSInvocation, objc_msgSend
当我们有方法名和参数列表,想要动态地给对象发送消息,可用通过反射函数机制来实现,有两种常用的做法:
一、performSelector
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
常用的方法有这三个,其中aSelector可以通过 NSSelectorFromString 方法拿到
SEL aSelector = NSSelectorFromString(selString);
但是 performSelector 的缺点是最多只支持传递两个参数
http://my.oschina.net/ososchina/blog/644117
这篇文章给出的方法二说是可以支持多参数,但是我尝试了下未成功
二、NSInvocation
不多说,直接上栗子
// 测试反射函数
- (void)printWithString:(NSString *)string withNum:(NSNumber *)number withArray:(NSArray *)array {
NSLog(@"%@, %@, %@", string, number, array[]);
} - (void)test {
NSString *str = @"哈哈哈";
NSNumber *num = @;
NSArray *arr = @[@"ABC", @"DEF"];
// [self printWithString:str withNum:num withArray:arr];
SEL sel = NSSelectorFromString(@"printWithString:withNum:withArray:");
NSArray *objs = [NSArray arrayWithObjects:str, num, arr, nil];
[self performSelector:sel withObjects:objs];
} - (id)performSelector:(SEL)selector withObjects:(NSArray *)objects
{
// 方法签名(方法的描述)
NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
if (signature == nil) { //可以抛出异常也可以不操作。
} // NSInvocation : 利用一个NSInvocation对象包装一次方法调用(方法调用者、方法名、方法参数、方法返回值)
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = selector; // 设置参数
NSInteger paramsCount = signature.numberOfArguments - ; // 除self、_cmd以外的参数个数
paramsCount = MIN(paramsCount, objects.count);
for (NSInteger i = ; i < paramsCount; i++) {
id object = objects[i];
if ([object isKindOfClass:[NSNull class]]) continue;
[invocation setArgument:&object atIndex:i + ];
} // 调用方法
[invocation invoke]; // 获取返回值
id returnValue = nil;
if (signature.methodReturnLength) { // 有返回值类型,才去获得返回值
[invocation getReturnValue:&returnValue];
} return returnValue;
}
三、objc_msgSend
objc_msgSend的写法要复杂一点,具体可以参看这篇文章,讲的很清楚
http://www.jianshu.com/p/efeb33712445
但是有个缺点是,需要指定好传递参数的类型,是不是可以直接都用id呢?
经测试id可用
// objc_msgSend
SEL sel = NSSelectorFromString(@"printWithString:withNum:withArray:");
((void (*) (id, SEL, NSString *, NSNumber *, NSArray *)) objc_msgSend) (self, sel, str, num, arr);
iOS 反射函数: performSelector, NSInvocation, objc_msgSend的更多相关文章
- iOS 消息处理之performSelector
//// RootViewController.h// DSCategories//// Created by dasheng on 15/12/17.// Copyright © 2015年 ...
- iOS 基础函数解析 - Foundation Functions Reference
iOS 基础函数解析 - Foundation Functions Reference 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名- ...
- iOS 反射 学习 和 运用
iOS 反射 学习 和 运用 反射: 通过 类名来获得生成的相应的类的实例 的这种机制 叫 反射 常用的反射方式 把 NSDictionary 转成 自定义 model 自定义 model 转 ...
- ios反射
http://www.cr173.com/html/18677_1.html 1.反射获取类属性名和属性类型 unsigned ; objc_property_t *properties = clas ...
- iOS多线程中performSelector: 和dispatch_time的不同
iOS中timer相关的延时调用,常见的有NSObject中的performSelector:withObject:afterDelay:这个方法在调用的时候会设置当前runloop中timer,还有 ...
- 我也要学iOS逆向工程--函数
大家好,这篇我开始学习函数了.先学 C 函数,然后再 OC 的吧.OC 应该复杂点的吧. 然后看看汇编情况哦! 学习函数呢,肯定要弄清楚几个事情. 1.跳转地址. 2.返回地址 3.参数 4.函数获取 ...
- iOS反射机制
iOS属性反射:说白了,就是将两个对象的所有属性,用动态的方式取出来,并根据属性名,自动绑值.(注意:对象的类,如果是派生类,就得靠其他方式来实现了,因为得到不该基类的属性.) 本人常用的反射方式,有 ...
- iOS多线程中performSelector
下面两段代码都在主线程中运行,我们在看别人代码时会发现有时会直接调用,有时会利用performSelector调用,今天看到有人在问这个问题,我便做一下总结, [delegate imageDownl ...
- U3D开发中关于脚本方面的限制-有关IOS反射和JIT的支持问题
U3D文档中说明了,反射在IOS是支持的,除了system.reflection.emit空间内的,其它都支持.JIT是不支持的. 本质上来说即是:只要不在运行时动态生成代码的行为都支持,reflec ...
随机推荐
- thinkphp实现登录后返回原界面
主要思路还是用session记录原地址,在登录后再跳转回原界面 先保存请求login方法界面的url public function savelogin(){ session('returnUrl', ...
- 前端 HTML-CSS 规范
黄金定律 一个项目应该永远遵循同一套编码规范! 不管有多少人共同参与同一项目,一定要确保每一行代码都像是同一个人编写的. HTML 语法 用两个空格来代替制表符(tab) – 这是唯一能保证在所有环境 ...
- OpenCV3的配置(VS2015)
1:首先下载和解压到给定的目录 2:设置环境变量...\build\x64\vc14\bin 3:打开VS,新建一个项目,再添加一个代码,刚开始当然是报错的 #include<opencv2\o ...
- mysql /etc/my.cnf
[client] port=3306 socket = /tmp/mysql.sock default-character-set=utf8 [mysqld] # 1 general config p ...
- spring框架详细课程视频
https://ke.qq.com/course/27346#term_id=100012852
- {ldelim},{rdelim} - smarty 内建函数
{ldelim}和{rdelim}用来转义模板的分隔符,缺省为{和}.你也可以用{literal}{/literal}来转义文本块(如Javascript或CSS). 例: {* 在模板外将原样打印分 ...
- MySQL三种存储引擎总结
MySQL三种存储引擎 MyISAM.InnoDB.MEMORY 1.MyISAM MyISAM,3.23.34a前的默认存储引擎. 优缺点 优点 在于占用空间小,处理速度快. 缺点 不支持事务的完整 ...
- ubuntu配置硬盘开机自动挂载
1.创建/media/fly文件夹 sudo mkdir /home/fly #根据个人喜好命名 2.获取要自动挂载的分区的UUID和分区类型TYPE sudo blkid 出现如下结果: ...
- 实现简单Restful API
1. 首选我们通过 http://start.spring.io/ 网址生成一个基础spring boot 项目,截图配置如下: 点击 generate Project 按钮生成并下载基础项目 2. ...
- 《Head First 设计模式》之单件模式
单件模式(Singleton) ——确保一个类只有一个实例,并提供全局访问点. 有一些对象其实我们只需要一个,比如线程池.缓存.对话框.处理偏好设置和注册表的对象.日志对象.如果制造出多个实例,就会导 ...