performSelector 方法的自己主动俘获特性
局部变量自己主动俘获
偶然在调试中发现,performSelector 方法具有自己主动俘获变量的特性。试看例如以下代码:
CGFloat c = _addViewShowing ? 0 : 80;
if([self respondsToSelector:@selector(jsq_setToolbarBottomLayoutGuideConstant:)]){
[self performSelector:@selector(jsq_setToolbarBottomLayoutGuideConstant:) withObject:nil];
...
}
这里请注意 [self performSelector:@selector(jsq_setToolbarBottomLayoutGuideConstant:) withObject:nil]; 一句。
在调用 performSelector 方法时,会自己主动把变量 CGFloat c 俘获到 jsq_setToolbarBottomLayoutGuideConstant: 方法调用中去。也就是说,相当于向该方法传递了參数 c。
值得注意的是。变量 c 的类型必须和 jsq_setToolbarBottomLayoutGuideConstant: 方法參数的类型同样。否则不会自己主动俘获。比如, c 变量为 CGFloat,而方法jsq_setToolbarBottomLayoutGuideConstant: 的參数同样也为 CGFloat:
- (void)jsq_setToolbarBottomLayoutGuideConstant:(CGFloat)constant
假设你将 c 的类型改成 int。则 c 不会被自己主动俘获。
利用这个特性,我们能够在 performSelector 调用时,自己主动传递变量给目标方法,而不用通过 withObject 来传參。
自己主动俘获方法參数
假设我们将上述代码定义为一个方法:
-(void)setToolbarSpaceToBottom:(CGFloat)constant{
// 调用私有方法 jsq_setToolbarBottomLayoutGuideConstant
CGFloat c = _addViewShowing ? 0 : 80;
if([self respondsToSelector:@selector(jsq_setToolbarBottomLayoutGuideConstant:)]){
[self performSelector:@selector(jsq_setToolbarBottomLayoutGuideConstant:) withObject:nil];
}
}
则变量 c 能够省略,由于 performSelector 会自己主动俘获方法參数 constant。将之传递给 jsq_setToolbarBottomLayoutGuideConstant: 调用。于是这种方法能够写成:
-(void)setToolbarSpaceToBottom:(CGFloat)constant{
if([self respondsToSelector:@selector(jsq_setToolbarBottomLayoutGuideConstant:)]){
[self performSelector:@selector(jsq_setToolbarBottomLayoutGuideConstant:) withObject:nil];
}
}
自己主动俘获的代价
上述代码同一时候会带来一个负面作用。即在两个 @selector 引用的地方出现两个同样编译警告:
Undeclared selector ‘jsq_setToolbarBottomLayoutGuideConstant:’
这是由于 jsq_setToolbarBottomLayoutGuideConstant: 方法来自于父类。它是私有的(没有将方法进行静态声明——即未在头文件里声明)。
对一切未静态声明的方法进行 performSelector 时。编译器都会提示 Undeclared selector。
你能够用以下的技术消除它们。但这会导致自己主动俘获失效。
不能使用自己主动俘获的情况
要消灭编译警告,我们能够使用 NSSelectorFromString 来引用 selector。
比如:
CGFloat c = constant;
SEL sel=NSSelectorFromString(@"jsq_setToolbarBottomLayoutGuideConstant:");
if([self respondsToSelector:sel]){
// 忽略编译器警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector:sel withObject:nil];
#pragma clang diagnostic pop
}
但这样的情况下。变量 c 不会被自己主动俘获。假设你在 jsq_setToolbarBottomLayoutGuideConstant: 方法的第一行代码加上断点执行程序。当程序执行到断点处时,打印參数的值,你会发现其值为 NaN 。假设继续执行代码。App 会崩溃。
这样的情况下。我们无法使用自己主动俘获,因此仅仅能使用 withObject 来传递參数了。
但由于 CGFloat 不是 NSObject,无法用 [performSelector: withObjectd:] 来传參。因此要使用 NSInvocation 来调用:
-(void)setToolbarSpaceToBottom:(CGFloat)constant{
SEL sel=NSSelectorFromString(@"jsq_setToolbarBottomLayoutGuideConstant:");
NSInvocation *invoc = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:sel]];
[invoc setSelector:sel];
[invoc setTarget:self];
[invoc setArgument:&constant atIndex:2];//"Indices 0 and 1 indicate the hidden arguments self and _cmd"
[invoc performSelector:@selector(invoke) withObject:nil];
}
performSelector 方法的自己主动俘获特性的更多相关文章
- 如何在方法上贴上attribute(特性)捕捉方法的异常,来实现我们的需求
在方法上贴上attribute(特性)捕捉方法的异常,其实这么做也是为了在项目中不会大量使用try-cacth这样的语句,同时使我们的代码看起来更简洁,更直观,将逻辑业务分离使得后期维护方便.这里我们 ...
- vue 父组件主动获取子组件的数据和方法 子组件主动获取父组件的数据和方法
Header.vue <template> <div> <h2>我是头部组件</h2> <button @click="getParen ...
- C#提高--------------获取方法返回值的自定义特性(Attribute)
.NET(C#):获取方法返回值的自定义特性(Attribute) 转载 2013年05月08日 10:54:42 1456 来自:http://www.cnblogs.com/mgen/archiv ...
- Swift里performSelector方法的替代
最近在回答StackOverflow的问题时,发现performSelector方法在Swift被去掉,Apple的注释是这个方法被去掉是因为不安全: NOTE The performSelector ...
- [Xcode 实际操作]八、网络与多线程-(19)使用RunLoop使PerformSelector方法延迟动作的执行
目录:[Swift]Xcode实际操作 本文将演示使用RunLoop使PerformSelector方法延迟动作的执行. 在项目导航区,打开视图控制器的代码文件[ViewController.swif ...
- C# 通过反射获取方法/类上的自定义特性
1.所有自定义属性都必须继承System.Attribute 2.自定义属性的类名称必须为 XXXXAttribute 即是已Attribute结尾 自定义属性QuickWebApi [Attribu ...
- 猫猫学iOS之小知识之_xcode插件的删除方法_自己主动提示图片插件KSImageNamed有时不灵_分类或宏之类不能自己主动提示,
猫猫分享,必须精品 原创文章.欢迎转载. 转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243 一:解决解决自己主动提示图片插件KSImageNamed有时不 ...
- [译]java9新特性:在接口中用pirvate方法让default(java8接口特性)更简练
Java8 带来了许多改变,其中之一就是default修饰的接口方法. 这些方法改变了我们已知的接口,现在我们能够在接口中定义默认实现方法.默认实现方法的不同之处在于,在接口中用default修饰抽象 ...
- 【.net 深呼吸】自定义特性(Attribute)的实现与检索方法
在.net的各个语言中,尤其是VB.NET和C#,都有特性这一东东,具体的概念,大家可以网上查,这里老周说一个非标准的概念——特性者,就是对象的附加数据.对象自然可以是类型.类型成员,以及程序集. 说 ...
随机推荐
- Hibernate 快速上手操作入门
本文主要是从技术操作角度去介绍hibernate,并且简单描述如何快速的上手操作hibernate,用于作为与数据库的连接的持久层. 简单讲述一下hibernate究竟是什么,它有什么作用,在理解它的 ...
- Python的程序结构[2] -> 类/Class[1] -> 基类与继承
基类与继承 / Base Class and Inheritance Class 面向对象的特性使得 Python 中不可避免地需要使用到类和类的继承,类的继承可以使得代码很好的被重用.下面以一些代码 ...
- 洛谷——P1100 高低位交换
P1100 高低位交换 题目描述 给出一个小于2^32的正整数.这个数可以用一个32位的二进制数表示(不足32位用0补足).我们称这个二进制数的前16位为“高位”,后16位为“低位”.将它的高低位交换 ...
- [JZOJ3106]锻炼
题目大意: 给你一个$n\times m(n,m\leq 50)$的网格图,其中有一个四连通的障碍物.给定起点和终点,每次你可以走到和当前位置八连通的一个方格内,问绕障碍物一圈最短要走几格? 思路: ...
- Unity3D的主要类图
原文:http://blog.teotigraphix.com/2011/05/17/unity3d-uml-gameobject-cheat-sheet/ 1. GameObject_Structu ...
- wget下载网站
命令格式如下: wget -r -p -np -k http://URL -r:在本机建立服务器端目录结构: -p: 下载显示HTML文件的所有图片: -np:只下载目标站点指定目录及其子目录的内容: ...
- Python学习笔记——基本数据结构
列表list List是python的一个内置动态数组对象,它的基本使用方式如下: shoplist = ['apple', 'mango', 'carrot', 'banana'] print 'I ...
- 任务驱动,学习.NET开发系列第2篇------单词统计
一 高效学习编程的办法 1 任务驱动方式学习软件开发 大部分人学习软件开发技术是通过看书,看视频,听老师上课的方式.这些方式有一个共同点即按知识点进行讲解.比如拿c#编程为例,首先是讲解大量的基础概念 ...
- MVC中自定义ViewPage和WebViewPage
ViewPage和WebViewPage的作用就是将Controller中数据返回给页面,一个是针对aspx一个相对cshtml的.代码如下: public abstract class WebVie ...
- hdu1008(c++)
分清上升停留下降一步步来就是了 #include<iostream>#include<vector>using namespace std;int main(){ int N, ...