objective-c 使用 -performSelector: vs. 只调用方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1493125/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using -performSelector: vs. just calling the method
提问by TheGambler
I'm still kind of new to Objective-C and I'm wondering what is the difference between the following two statements?
我对 Objective-C 还是有点陌生,我想知道以下两个语句之间有什么区别?
[object performSelector:@selector(doSomething)];
[object doSomething];
回答by ennuikiller
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.
基本上 performSelector 允许您动态确定哪个选择器调用给定对象上的选择器。换句话说,不需要在运行时之前确定选择器。
Thus even though these are equivalent:
因此,即使这些是等效的:
[anObject aMethod];
[anObject performSelector:@selector(aMethod)];
The second form allows you to do this:
第二种形式允许你这样做:
SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];
before you send the message.
在您发送消息之前。
回答by Motti Shneor
For this very basic example in the question,
对于问题中的这个非常基本的例子,
[object doSomething];
[object performSelector:@selector(doSomething)];
there is no difference in what is going to happen. doSomething will be synchronously executed by object. Only "doSomething" is a very simple method, that does not return anything, and does not require any parameters.
将要发生的事情没有区别。doSomething 将被对象同步执行。只有“doSomething”是一个非常简单的方法,它不返回任何东西,也不需要任何参数。
were it something a little more complicated, like:
是不是有点复杂,比如:
(void)doSomethingWithMyAge:(NSUInteger)age;
things would get complicated, because [object doSomethingWithMyAge:42];
事情会变得复杂,因为 [object doSomethingWithMyAge:42];
can no longer be called with any variant of "performSelector", because all variants with parameters only accept object parameters.
不能再用“performSelector”的任何变体调用,因为所有带参数的变体只接受对象参数。
The selector here would be "doSomethingWithMyAge:" but any attempt to
这里的选择器将是“doSomethingWithMyAge:”,但任何尝试
[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];
simply won't compile. passing an NSNumber: @(42) instead of 42, wouldn't help either, because the method expects a basic C type - not an object.
根本不会编译。传递一个 NSNumber:@(42) 而不是 42,也无济于事,因为该方法需要一个基本的 C 类型 - 而不是一个对象。
In addition, there are performSelector variants up to 2 parameters, no more. While methods many times have many more parameters.
此外,还有最多 2 个参数的 performSelector 变体,仅此而已。虽然方法很多时候有更多的参数。
I have found out that although synchronous variants of performSelector:
我发现虽然 performSelector 的同步变体:
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
always return an object, I was able to return a simple BOOL or NSUInteger too, and it worked.
总是返回一个对象,我也能够返回一个简单的 BOOL 或 NSUInteger,并且它起作用了。
One of the two main uses of performSelector is to compose dynamically the name of the method you want to execute, as explained in a previous answer. For example
performSelector 的两个主要用途之一是动态组合要执行的方法的名称,如上一个答案中所述。例如
SEL method = NSSelectorFromString([NSString stringWithFormat:@"doSomethingWithMy%@:", @"Age");
[object performSelector:method];
The other use, is to asynchronously dispatch a message to object, that will be executed later on the current runloop. For this, there are several other performSelector variants.
另一种用途是将消息异步分派给对象,该消息稍后将在当前 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;
(yes I gathered them from several Foundation class categories, like NSThread, NSRunLoop and NSObject)
(是的,我从几个 Foundation 类类别中收集了它们,例如 NSThread、NSRunLoop 和 NSObject)
Each of the variants has its own special behavior, but all share something in common (at least when waitUntilDone is set to NO). The "performSelector" call would return immediately, and the message to object will only be put on the current runloop after some time.
每个变体都有自己的特殊行为,但都有一些共同点(至少当 waitUntilDone 设置为 NO 时)。"performSelector" 调用会立即返回,并且对象的消息将在一段时间后才会放在当前的 runloop 上。
Because of the delayed execution - naturally no return value is available form the method of the selector, hence the -(void) return value in all these asynchronous variants.
由于延迟执行 - 自然没有返回值可从选择器的方法中获得,因此所有这些异步变体中的 -(void) 返回值。
I hope I covered this somehow...
我希望我以某种方式涵盖了这个......
回答by Quinn Taylor
@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.
@ennukiller 恰到好处。基本上,动态生成的选择器在您不(并且通常不可能)知道编译代码时将调用的方法的名称时很有用。
One key difference is that -performSelector:and friends (including the multi-threaded and delayed variants) are somewhat limited in that they are designed for use with methods with 0-2 parameters. For example, calling -outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:with 6 parameters and returning the NSStringis pretty unwieldy, and not supported by the provided methods.
一个关键的区别是,-performSelector:和朋友(包括多线程和延迟变体)在某种程度上受到限制,因为它们被设计为与具有 0-2 个参数的方法一起使用。例如,-outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:使用 6 个参数调用并返回NSString非常笨拙,并且不支持提供的方法。
回答by Daniel Yankowsky
Selectors are a bit like function pointers in other languages. You use them when you don't know at compile time which method you want to call at runtime. Also, like function pointers, they only encapsulate the verb part of invocation. If the method has parameters, you will need to pass them as well.
选择器有点像其他语言中的函数指针。当您在编译时不知道要在运行时调用哪个方法时,您可以使用它们。此外,与函数指针一样,它们仅封装调用的动词部分。如果该方法有参数,您也需要传递它们。
An NSInvocationserves a similar purpose, except that it binds together more information. Not only does it include the verb part, it also includes the target object and the parameters. This is useful when you want to call a method on a particular object with particular parameters, not now but in the future. You can build an appropriate NSInvocationand fire it later.
AnNSInvocation服务于类似的目的,不同之处在于它将更多信息绑定在一起。它不仅包括动词部分,还包括目标对象和参数。当您想在具有特定参数的特定对象上调用方法时,这非常有用,不是现在而是将来。您可以构建一个适当的NSInvocation并稍后触发它。
回答by avi
There is another subtle difference between the two.
两者之间还有另一个微妙的区别。
[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: Performs the specified selector on the current thread during the next run loop cycle and after an optional delay period. Because it waits until the next run loop cycle to perform the selector, these methods provide an automatic mini delay from the currently executing code. Multiple queued selectors are performed one after another in the order they were queued."
"performSelector:withObject:afterDelay: 在下一个运行循环周期和一个可选的延迟期之后,在当前线程上执行指定的选择器。因为它会等到下一个运行循环循环执行选择器,所以这些方法提供了从当前正在执行的代码。多个排队的选择器按照它们排队的顺序一个接一个地执行。”

