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];
}
时间: 2024-10-07 04:22:00

performSelector 方法的自己主动俘获特性的相关文章

Swift里performSelector方法的替代

最近在回答StackOverflow的问题时,发现performSelector方法在Swift被去掉,Apple的注释是这个方法被去掉是因为不安全: NOTE The performSelector: method and related selector-invoking methods are not imported in Swift because they are inherently unsafe. 如果在Swift调用这个方法会编译出错: 'performSelector' is

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

猫猫分享,必须精品 原创文章.欢迎转载. 转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243 一:解决解决自己主动提示图片插件KSImageNamed有时不灵_分类或宏之类不能自己主动提示 事实上.插件神马的我们自己也能写.并没有想象中的那么难,只是眼下我们还是先解决当前问题 在做微博项目时候.抽取的分类有一个 +(instancetype)imageWithOriginalName:(NSString *)imageName; 可是调用的时候,当中字

oc消息发送机制之performSelector方法的扩充

本文摘自别的博客 各种语言都有些传递函数的方法:C语言中可以使用函数指针,C++中有函数引用.仿函数和lambda,Objective-C里也有选择器(selector)和block. 不过由于iOS SDK中的大部分API都是selector的方式,所以本文就重点讲述selector了.Objective-C和我接触过的其他面向对象的语言不同,它强调消息传递,而非方法调用.因此你可以对一个对象传递任何消息,而不需要在编译期声名这些消息的处理方法. 很显然,既然编译期并不能确定方法的地址,那么运

OC -- (SEL)oc中消息传递机制-附:对performSelector方法的扩充

原文地址: http://www.cnblogs.com/ygm900/archive/2013/01/16/2862676.html 各种语言都有些传递函数的方法:C语言中可以使用函数指针,C++中有函数引用.仿函数和lambda,Objective-C里也有选择器(selector)和block.不过由于iOS SDK中的大部分API都是selector的方式,所以本文就重点讲述selector了.Objective-C和我接触过的其他面向对象的语言不同,它强调消息传递,而非方法调用.因此你

神手微信CMR营销管理,有什么方法让客户主动找我?

微信不单单是一个社交软件了,它不仅影响了大家的社交方式,也影响了网络营销的模式,但微信和QQ相比是较封闭的,那么在微信营销中,有没有让客户主动来找你的方法呢? 微信用朋友圈做口碑传播,然后进行精准引流做微信营销,微信营销现在也已经成为了目目前移动网络营销的最佳方式,做营销肯定是圈子越广越好,接下来和大家说说让粉丝主动找你的5大微信营销技巧! 1.挖粉丝圈 先要自己培养一批种子粉丝并做好维护,在借助粉丝的微信端进行分享在.这是通过粉丝的信任度来发展期微信圈的用户,并以此类推,就可以深度的挖掘粉子圈

jQuery中用attr()方法来获取和设置特性

开始也逐步用C++替代.NET开发了.公司的业务剩下使用.NET开发的项目已经不是很多,掰着指头就可以数得过来,目前还有财经/行政/HR/财付通/互娱一些运营系统还是使用.NET开发.如果只能部署在Windows平台上,这些系统迟早要被替换掉.因此,我在做腾讯OA基础服务TOF的维护的同时,业余时间在研究Mono跨平台开发,通过博客,微搏宣传Mono项目,并在实践中进行实践. 最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求——国际化&本地化.熟悉的是之前的项目也玩过,陌

Lua的方法的一些特性--lua和android

学习lua不得不了解其方法或者说语法的特性,比如:多值返回 function maximum (a) local mi = 1 -- maximum index local m = a[mi] -- maximum value for i,val in ipairs(a) do if val > m then mi = i m = val end end return m, mi end print(maximum({8,10,23,12,5})) --> 23 3 可变参数 function

对属性特性操作的三个主要方法(创建,设置,删除)

每个元素都有一个或多个特性,这些特性给相应元素或内容附加信息.操作特性的DOM的方法主要有三种 分别是getAttribute().setAttribute().removeAttribute(). getAttribute()方法主要用于获取属性值 任何元素的所有属性,也都可以通过getAttirbute方法来获取器属性值. 例如: 在HTML中:<div id="mydiv" class="class" mychakk="mychakk"

java8新特性-默认方法

作为一个java程序猿,经常会被问基础怎么样,对于这个问题,我理解的有两方面:一是对于java基础的理解和掌握,比如JDK的相关特性:二是工作的经历,毕竟,语言编程是一门实战性质的艺术,就算掌握了千万理论,编写不出实际的代码,等于扯淡.而且,随着技术的革新,很多东西都不再是一成不变的,还记得刚出校门那会儿,面试官会问接口与类的区别啥的,大多人会回答:接口里面的全是抽象方法.这个回答在现在看来,或许已经过时了,随着JDK1.8的推出,接口里面也是可以有方法实现的.所以,在这里总结一下JDK1.8的