使用-performSelector:与仅调用方法

时间:2009-09-29 15:01:14

标签: objective-c selector dynamic-languages method-dispatch

我仍然是Objective-C的新手,我想知道以下两个陈述之间有什么区别?

[object performSelector:@selector(doSomething)]; 

[object doSomething];

5 个答案:

答案 0 :(得分:186)

基本上,performSelector允许您动态确定在给定对象上调用选择器的选择器。换句话说,选择器不需要在运行时之前确定。

因此即使这些是等价的:

[anObject aMethod]; 
[anObject performSelector:@selector(aMethod)]; 

第二种形式允许您这样做:

SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];

发送邮件之前。

答案 1 :(得分:13)

对于问题中这个非常基本的例子,

[object doSomething];
[object performSelector:@selector(doSomething)]; 

即将发生的事情没有区别。 doSomething将由对象同步执行。只有" doSomething"是一个非常简单的方法,它不会返回任何内容,也不需要任何参数。

它有点复杂,比如:

(void)doSomethingWithMyAge:(NSUInteger)age;
事情会变得复杂,因为     [object doSomethingWithMyAge:42];

不能再使用" performSelector"的任何变体调用,因为所有带参数的变体只接受对象参数。

这里的选择器将是&#34; doSomethingWithMyAge:&#34; <尝试

[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];  

简单地不会编译。通过一个NSNumber:@(42)而不是42,也不会有任何帮助,因为该方法需要一个基本的C类型 - 而不是一个对象。

此外,还有最多2个参数的performSelector变体。虽然方法多次有更多参数。

我发现虽然performSelector的同步变种:

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

总是返回一个对象,我也可以返回一个简单的BOOL或NSUInteger,并且它有效。

performSelector的两个主要用途之一是动态组合要执行的方法的名称,如上一个答案中所述。例如

 SEL method = NSSelectorFromString([NSString stringWithFormat:@"doSomethingWithMy%@:", @"Age");
[object performSelector:method];

另一种用法是异步地将消息分派给对象,稍后将在当前的runloop上执行。为此,还有其他几个performSelector变体。

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
- (void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray *)modes;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;

(是的,我从几个基础课程类别中收集了它们,如NSThread,NSRunLoop和NSObject)

每个变体都有自己的特殊行为,但都共享一些共同点(至少当waitUntilDone设置为NO时)。 &#34; performSelector&#34; call会立即返回,并且对象的消息只会在一段时间后放在当前的runloop上。

由于执行延迟 - 自然没有返回值可供选择器的方法使用,因此所有这些异步变量中的 - (void)返回值。

我希望我以某种方式涵盖了这一点......

答案 2 :(得分:11)

@ennuikiller是现货。基本上,当您编译代码时(或通常不可能)知道您将在调用代码时调用的方法的名称时,动态生成的选择器非常有用。

一个关键的区别是-performSelector:和朋友(包括multi-threaded and delayed variants)在某种程度上受到限制,因为它们被设计用于具有0-2参数的方法。例如,使用6个参数调用-outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:并返回NSString非常笨拙,并且所提供的方法不支持。

答案 3 :(得分:3)

选择器有点像其他语言中的函数指针。如果在编译时不知道要在运行时调用哪个方法,则可以使用它们。此外,与函数指针一样,它们仅封装调用的动词部分。如果方法有参数,您也需要传递它们。

NSInvocation具有类似的用途,除了它将更多信息绑定在一起。它不仅包括动词部分,还包括目标对象和参数。当您想要使用特定参数调用特定对象的方法时,这非常有用,而不是现在,而是将来。您可以构建适当的NSInvocation并稍后启动它。

答案 4 :(得分:-7)

两者之间还有另一个微妙的区别。

    [object doSomething]; // is executed right away

    [object performSelector:@selector(doSomething)]; // gets executed at the next runloop

以下是Apple文档的摘录

“performSelector:withObject:afterDelay: 在下一个运行循环周期和可选的延迟周期之后,在当前线程上执行指定的选择器。因为它等待直到下一个运行循环周期来执行选择器,所以这些方法提供了来自当前执行代码的自动迷你延迟。多个排队的选择器按照它们排队的顺序一个接一个地执行。“