使用-PerformSelector: vs. 只调用方法

我对 Objective-C 还是个新手,我想知道下面两个语句之间的区别是什么?

[object performSelector:@selector(doSomething)];


[object doSomething];
65232 次浏览

Basically performSelector allows you to dynamically determine which selector to call a selector on the given object. In other words the selector need not be determined before runtime.

因此,即使这两者是等价的:

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

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

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

在你发送信息之前。

@ennuikiller is spot on. Basically, dynamically-generated selectors are useful for when you don't (and usually can't possibly) know the name of the method you'll be calling when you compile the code.

一个关键的区别是,-performSelector:和朋友(包括 多线程和延迟变体)在某种程度上是有限的,因为它们是为使用具有0-2个参数的方法而设计的。例如,使用6个参数调用 -outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:并返回 NSString是相当笨拙的,并且不受提供的方法的支持。

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

NSInvocation也有类似的用途,只不过它将更多的信息绑定在一起。它不仅包括动词部分,还包括目标对象和参数。当您希望对具有特定参数的特定对象调用方法时(不是现在,而是将来) ,这非常有用。您可以构建一个适当的 NSInvocation并在以后激发它。

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

    [object doSomething]; // is executed right away


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

Here is the excerpt from Apple Documentation

"performSelector:withObject:afterDelay: 在下一个运行循环周期和可选的延迟期之后,对当前线程执行指定的选择器。因为它要等到下一个运行循环周期才能执行选择器,所以这些方法从当前正在执行的代码提供了一个自动的小延迟。多个排队选择器按照排队顺序一个接一个地执行。”

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

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

将要发生的事情没有什么不同。DoSomething 将由 object 同步执行。只有“ doSomething”是一个非常简单的方法,它不返回任何内容,也不需要任何参数。

是不是更复杂一点,比如:

(void)doSomethingWithMyAge:(NSUInteger)age;

事情会变得复杂,因为 [ object doSomething WithMyAge: 42] ;

不能再使用任何变体“ PerformSelector”调用,因为所有具有参数的变体都只接受对象参数。

这里的选择器将是“ doSomething WithMyAge:”,但是任何尝试

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

就是编译不了。传递一个 NSNumber:@(42)而不是42也不会有帮助,因为该方法需要一个基本的 C 类型——而不是一个对象。

In addition, there are performSelector variants up to 2 parameters, no more. While methods many times have many more parameters.

我发现,虽然 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];

另一个用途是异步发送消息到对象,稍后将在当前运行循环中执行该消息。为此,还有其他一些 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 时是如此)。“ PerformSelector”调用将立即返回,并且对象的消息只会在一段时间后才会放到当前的运行循环中。

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

我希望我能想办法掩盖这件事。