局部变量自己主动俘获

偶然在调试中发现,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 方法的自己主动俘获特性的更多相关文章

  1. 如何在方法上贴上attribute(特性)捕捉方法的异常,来实现我们的需求

    在方法上贴上attribute(特性)捕捉方法的异常,其实这么做也是为了在项目中不会大量使用try-cacth这样的语句,同时使我们的代码看起来更简洁,更直观,将逻辑业务分离使得后期维护方便.这里我们 ...

  2. vue 父组件主动获取子组件的数据和方法 子组件主动获取父组件的数据和方法

    Header.vue <template> <div> <h2>我是头部组件</h2> <button @click="getParen ...

  3. C#提高--------------获取方法返回值的自定义特性(Attribute)

    .NET(C#):获取方法返回值的自定义特性(Attribute) 转载 2013年05月08日 10:54:42 1456 来自:http://www.cnblogs.com/mgen/archiv ...

  4. Swift里performSelector方法的替代

    最近在回答StackOverflow的问题时,发现performSelector方法在Swift被去掉,Apple的注释是这个方法被去掉是因为不安全: NOTE The performSelector ...

  5. [Xcode 实际操作]八、网络与多线程-(19)使用RunLoop使PerformSelector方法延迟动作的执行

    目录:[Swift]Xcode实际操作 本文将演示使用RunLoop使PerformSelector方法延迟动作的执行. 在项目导航区,打开视图控制器的代码文件[ViewController.swif ...

  6. C# 通过反射获取方法/类上的自定义特性

    1.所有自定义属性都必须继承System.Attribute 2.自定义属性的类名称必须为 XXXXAttribute 即是已Attribute结尾 自定义属性QuickWebApi [Attribu ...

  7. 猫猫学iOS之小知识之_xcode插件的删除方法_自己主动提示图片插件KSImageNamed有时不灵_分类或宏之类不能自己主动提示,

    猫猫分享,必须精品 原创文章.欢迎转载. 转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243 一:解决解决自己主动提示图片插件KSImageNamed有时不 ...

  8. [译]java9新特性:在接口中用pirvate方法让default(java8接口特性)更简练

    Java8 带来了许多改变,其中之一就是default修饰的接口方法. 这些方法改变了我们已知的接口,现在我们能够在接口中定义默认实现方法.默认实现方法的不同之处在于,在接口中用default修饰抽象 ...

  9. 【.net 深呼吸】自定义特性(Attribute)的实现与检索方法

    在.net的各个语言中,尤其是VB.NET和C#,都有特性这一东东,具体的概念,大家可以网上查,这里老周说一个非标准的概念——特性者,就是对象的附加数据.对象自然可以是类型.类型成员,以及程序集. 说 ...

随机推荐

  1. Javascript中call、apply函数浅析

    call/apply函数作用其实就是改变this的取值,有一句话是:谁调用的这个方法那方法里的this就是指谁,而有时我们会需要改变this值,所以call/apply就能派上用场. 下面我写个方法来 ...

  2. Codeforces Round #164 (Div. 2) A. Games【暴力/模拟/每个球队分主场和客场,所有球队两两之间进行一场比赛,要求双方球服颜色不能相同】

    A. Games time limit per test 1 second memory limit per test 256 megabytes input standard input outpu ...

  3. 线段树【 bzoj3132 】【p4145 】上帝造题的七分钟2 / 花神游历各国

    题目大意 给定一个区间 支持开方和查询区间值操作 (多组数据 分析 如果一个区间的最大值小于1,那就没有开方的必要了(具体不会证明,听大佬讲的 一个数经过多次开方就会变成1(可以用计算器试一下 因此我 ...

  4. Java-静态代码块,构造代码块,构造函数

    静态代码块:用staitc声明,jvm加载类时执行,仅执行一次 构造代码块:类中直接用{}定义,每一次创建对象时执行. 执行顺序优先级:静态块, main(),函数,构造块,构造方法. 构造函数 pu ...

  5. 【bzoj1085】【 [SCOI2005]骑士精神】启发式剪枝+迭代加深搜索

    (上不了p站我要死了,侵权度娘背锅) 如果这就是启发式搜索的话,那启发式搜索也不是什么高级玩意嘛..(啪啪打脸) Description 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且 ...

  6. 1.13抽象类及接口(附简述final关键字)

    一.final final的中文意思就是不可更改的,最终的. 1.final修饰变量,那么该变量无法更改.一旦该变量赋了初值,就不能重新赋值. final MAX = 1100; //final修饰后 ...

  7. 八. 输入输出(IO)操作4.面向字节的输入输出流

    字节流以字节为传输单位,用来读写8位的数据,除了能够处理纯文本文件之外,还能用来处理二进制文件的数据.InputStream类和OutputStream类是所有字节流的父类. InputStream类 ...

  8. 开源 ≠ 免费,开源协议License详解

    凡是做过软件开发的,都会接触到开源软件或开源组件,它们都会基于某种协议来提供源码和授权,那么这些开源协议到底有哪些约束呢? 在介绍之前,必须告诉大家,针对开源协议,必须打消“开源 = 免费”这个念头, ...

  9. UVa1347 Tour

    /*----UVa1347 ---首相两边方向走不方便,可以看做:两个人同时从最左边出发,沿着两条不同路径走到终点,除了起点和中点外 其他点恰好被走过一遍 ---用dp[i][j]表示1-max(i, ...

  10. git push后自动部署

    前提,服务器已经装好ssh,本地也已经将ssh 公钥传到服务器对应位置 先用 pbcopy < ~/.ssh/PRIVATE_KEY.pub 将公钥复制到剪贴板:通过 ssh USER@SERV ...