performselector

时间:2026-01-14 12:47:21编辑:莆田seo君

在OC 中,给对象发送一个消息,与 通过@selector 发送一个消息有什么区别 ?

不知道你的基础如何? 我就简单说一点吧。例如People类继承于NSObject, 它有一个eat方法。 你创建了一个对象People *p = [People new];然后你可以使用[p eat]或者 [p perfomSelector:@selector(eat)]来。两种到底有什么区别? 其实对于方法调用本身来说,都是调用eat方法,但是performSelector提供了一种间接性,它可以通过传入不同的selector来调用不同的方法。[p eat]对于编译器来说,内部应该会编译成[p performSelector:@selector(eat)]的方法,这个是我的猜想。 然后在运行时期,根据@selector(eat)得到的方法字符串SEL得到eat方法的实现代码的函数指针IMP, 然后调用以C语言的方式使用eatImp(p, @selector(eat);来调用eat方法。实际上对于上面的两个区别,你可能会用到的是这种情况。在头文件.h中你不声明eat,在外部使用People时候,你不能使用[p eat],但你可以使用performSelector的方式,这是由于编译器在[p eat]就根本不让你编译通过, performSelector是运行期的事情,编译器只会给出警告,不会阻拦你,会有更好的灵活性。对于上面两个方法还有一点,performSelector相当于是一个控制中心,它可以接收selector来进行调用不同的方法。这相当于apple给我们一个自己统一处理方法的机会。例如我们需要做一个消息控制中心,根据不同的消息调用不同的方法,我可以写出这样的代码:void processMethodByMsg:(NSString*)methodName{ NSDictionary* methodDic = @{@"eat": @selector(eat), @"drink":@selector(drink), @"sleep":@selector(sleep)}; [p performSelector:methodDic[methodName]];}通过一个dic就完成了字符串和方法的映射,methodName是由外部输入的消息名字,需要修改或者添加的时候,你仅仅需要修改dic词典就可以了,完成了代码的归一。好了,啰啰嗦嗦十分钟了,希望能给你一些帮助。


ios里消息和 selector 的区别是什么

区别一:delegate针对one-to-one关系,并且reciever可以返回值给sender;notification 可以针对one-to-one/many/none,reciever无法返回值给sender;所以,delegate用于sender希望接受到reciever的某个功能反馈值,notification用于通知多个object某个事件。
  区别二:
  Delegate:消息的发送者(sender)告知接收者(receiver)某个事件将要发生,delegate同意然后发送者响应事件,delegate机制使得接收者可以改变发送者的行为。通常发送者和接收者的关系是直接的一对多的关系。
  Notification:
消息的发送者告知接收者事件已经发生或者将要发送,仅此而已,接收者并不能反过来影响发送者的行为。通常发送者和接收者的关系是间接的多对多关系。
  区别三:效率肯定是delegate比nsnotification高。
区别四:delegate方法比notification更加直接,最典型的特征是,delegate方法往往需要关注返回值,也就是delegate方法的结果。
  delegate用于声明委托。Notification用于通告。委托是一种引用类型,引用类型的 Shared 方法或对象的实例方法。任何具有匹配参数类型和返回类型的过程均可用来创建此委托类的实例。然后就可以通过委托实例来调用过程。


关于performSelector调用和直接调用有什么不同

1. 有一点是肯定的, performSelector是运行时系统负责去找函数/方法的,在编译时候不做任何校验;但是直接调用肯定在编译是会校验。如果test2不存在,那么直接调用 在编译时候就能够发现(借助Xcode可以写完就发现),但是使用performSelector的话一定是在运行时候才能发现(此时程序崩溃)
Cocoa支持在运行时 向某个类添加方法(应该极少人用到, 即方法编译时不存在,但是运行时候存在,这时候必然需要使用performSelector去调用)
大概这也是为什么写delegate的时候,为保证程序健壮性,会使用如下函数检验
- (BOOL)respondsToSelector:(SEL)aSelector;


请教个performselector延时执行的问题问题

实际上是performSelector延时调用的问题,经查找资料,performSelector关于内存管理的执行原理是这样的执行 [self performSelector:@selector(method1:) withObject:self.tableLayer afterDelay:3]; 的时候,系统会将tableLayer的引用计数加1,执行完这个方法时,还会将tableLayer的引用计数减1,而在我的游戏里这个延时执行函数是被多次调用的,有时切换场景时延时函数已经被调用但还没有执行,这时tableLayer的引用计数没有减少到0,也就导致了切换场景dealloc方法没有被调用,出现了内存泄露。
所以最后我的解决办法就是取消那些还没有来得及执行的延时函数,代码很简单:
[NSObject cancelPreviousPerformRequestsWithTarget:self]
当然你也可以一个一个得这样用:
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(method1:) object:nil]
加上了这个以后,切换场景也就很顺利地执行了dealloc方法,至此问题解决!

最后在找资料时也发现了,延时调用实现长按钮的实现思路,记录下来以备后用:
在touchBegan里面
[self performSelector:@selector(longPressMethod:) withObject:nil afterDelay:longPressTime]
然后在end 或cancel里做判断,如果时间不够长按的时间调用:
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(longPressMethod:) object:nil]
取消began里的方法

最后最后总结:
performSelector是一个很有用的函数,跟它打过不少交道,经过血与泪的教训,总结一下它的使用如下:
使用前先检测一下,
SEL testSelector = @selector(test:);
if([tester respondsToSelector:testSelector])
{
//如果响应就执行
[tester test:@"invoke test method"];
}
使用后,如果有必要,需要显示的调用cancelPreviousPerformRequestsWithTarget:selector:object: ,否则有可能产生内存泄露,而且这种内存泄露很难发现,因为它并不违反任何规则,所以一定要注意!


关于performSelector调用和直接调用有什么不同

下面两段代码都在主线程中运行,我们在看别人代码时会发现有时会直接调用,有时会利用performSelector调用,今天看到有人在问这个问题,我便做一下总结,
[delegate imageDownloader:self didFinishWithImage:image];
[delegate performSelector:@selector(imageDownloader:didFinishWithImage:)withObject:self withObject:image];

1、performSelector是运行时系统负责去找方法的,在编译时候不做任何校验;如果直接调用编译是会自动校验。如果imageDownloader:didFinishWithImage:image:不存在,那么直接调用 在编译时候就能够发现(借助Xcode可以写完就发现),但是使用performSelector的话一定是在运行时候才能发现(此时程序崩溃);Cocoa支持在运行时向某个类添加方法,即方法编译时不存在,但是运行时候存在,这时候必然需要使用performSelector去调用。所以有时候如果使用了performSelector,为了程序的健壮性,会使用检查方法
- (BOOL)respondsToSelector:(SEL)aSelector;
2、直接调用方法时候,一定要在头文件中声明该方法的使用,也要将头文件import进来。而使用performSelector时候, 可以不用import头文件包含方法的对象,直接用performSelector调用即可。


上一篇:w2016

下一篇:没有了