使用 -performSelector: 与仅调用方法

发布于 2024-08-05 22:39:00 字数 143 浏览 12 评论 0原文

我对 Objective-C 还是个新手,我想知道以下两个语句有什么区别?

[object performSelector:@selector(doSomething)]; 

[object doSomething];

I'm still kind of new to Objective-C and I'm wondering what is the difference between the following two statements?

[object performSelector:@selector(doSomething)]; 

[object doSomething];

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

戈亓 2024-08-12 22:39:00

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

因此,即使它们是等效的:

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

第二种形式允许您执行此操作:

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

在发送消息之前。

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.

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.

寄离 2024-08-12 22:39:00

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

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

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

是不是有点复杂,比如:

(void)doSomethingWithMyAge:(NSUInteger)age;

事情会变得复杂,因为
[对象 doSomethingWithMyAge:42];

不能再使用“performSelector”的任何变体进行调用,因为所有带有参数的变体仅接受对象参数。

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

[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];

,另一个用途是将消息异步分派给对象,该消息稍后将在当前运行循环上执行。为此,还有其他几种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) 返回值。

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

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.

were it something a little more complicated, like:

(void)doSomethingWithMyAge:(NSUInteger)age;

things would get complicated, because
[object doSomethingWithMyAge:42];

can no longer be called with any variant of "performSelector", because all variants with parameters only accept object parameters.

The selector here would be "doSomethingWithMyAge:" but any attempt to

[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.

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

I have found out that although synchronous variants of 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.

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

 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.

- (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)

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.

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.

I hope I covered this somehow...

冷︶言冷语的世界 2024-08-12 22:39:00

@ennukiller 说得对。基本上,当您不(通常不可能)知道编译代码时要调用的方法的名称时,动态生成的选择器非常有用。

一个关键区别是 -performSelector: 和朋友(包括 多线程和延迟变体) 有一定的局限性,因为它们被设计用于具有 0-2 个参数的方法。例如,调用 -outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation: 带有 6 个参数并返回 NSString 非常笨拙,并且提供的方法不支持。

@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.

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 NSString is pretty unwieldy, and not supported by the provided methods.

彼岸花似海 2024-08-12 22:39:00

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

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

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 NSInvocation serves 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 NSInvocation and fire it later.

醉生梦死 2024-08-12 22:39:00

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

    [object doSomething]; // is executed right away

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

以下是 Apple 文档“performSelector:withObject:afterDelay”的摘录


在下一个运行循环周期期间以及可选的延迟期之后,在当前线程上执行指定的选择器。因为它会等到下一个运行循环周期才执行选择器,所以这些方法提供了当前执行代码的自动微延迟。多个排队选择器按照它们排队的顺序依次执行。”

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."

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文