局部变量自己主动俘获

偶然在调试中发现,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. 51nod 1087 1 10 100 1000【打表】

    题目来源: Ural 1209 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题  收藏  关注 1,10,100,1000...组成序列1101001000...,求 ...

  2. FZU-2219 StarCraft(贪心)

     Problem 2219 StarCraft Accept: 294    Submit: 860Time Limit: 1000 mSec    Memory Limit : 32768 KB   ...

  3. jcl sort comp3 to 表示型

    Lets say your packed data is at 10th column and is of length 6, S9(4)V99 You could try the following ...

  4. Moving Average from Data Stream -- LeetCode

    Given a stream of integers and a window size, calculate the moving average of all integers in the sl ...

  5. 洛谷 U19159 采摘毒瘤

    题目背景 Salamander见到路边有如此多的毒瘤,于是见猎心喜,从家里拿来了一个大袋子,准备将一些毒瘤带回家. 题目描述 路边共有nn 种不同的毒瘤,第i 种毒瘤有k_i 个,每个需要占据d_i  ...

  6. [LOJ6278]数列分块入门 2

    题目大意: 给你一个长度为$n(n\leq 50000)$的序列$A$,支持进行以下两种操作: 1.将区间$[l,r]$中所有数加上$c$: 2.询问区间$[l,r]$中小于$c^2$的数的个数.思路 ...

  7. 怎样设计REST中间件---中间件JSON对数据库数据的组织

    怎样设计REST中间件---中间件JSON对数据库数据的组织 SQL查询语句有:select SQL非查询语句有:insert, update, delete 三种 中间件JSON对数据库数据的组织也 ...

  8. ASIHTTPREQUEST framework compile error when method is called / link error

    never mind!!! duplicate: Error with iOS 5.1 when i use ASIHTTPRequest and SBJSON "I would take ...

  9. 修改weblogic端口的方法

    修改weblogic的端口常用的有两种方法 方法一.登录weblogic的console.如:http://localhost:7001/console/ 1).在环境--服务器节点中点击你要修改的服 ...

  10. python urllib2使用细节

    刚好用到,这篇文章写得不错,转过来收藏.    转载自 道可道 | Python 标准库 urllib2 的使用细节 Python 标准库中有很多实用的工具类,但是在具体使用时,标准库文档上对使用细节 ...