我对 Objective-C 还是有点陌生,我想知道以下两个语句之间有什么区别?
[object performSelector:@selector(doSomething)];
[object doSomething];
我对 Objective-C 还是有点陌生,我想知道以下两个语句之间有什么区别?
[object performSelector:@selector(doSomething)];
[object doSomething];
基本上 performSelector 允许您动态确定在给定对象上调用哪个选择器。换句话说,选择器不需要在运行前确定。
因此,即使这些是等价的:
[anObject aMethod];
[anObject performSelector:@selector(aMethod)];
第二种形式允许您这样做:
SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];
在您发送消息之前。
对于问题中的这个非常基本的示例,
[object doSomething];
[object performSelector:@selector(doSomething)];
将要发生的事情没有区别。doSomething 将由对象同步执行。只有“doSomething”是一个非常简单的方法,它不返回任何东西,也不需要任何参数。
是不是更复杂一些,比如:
(void)doSomethingWithMyAge:(NSUInteger)age;
事情会变得复杂,因为 [object doSomethingWithMyAge:42];
不能再用“performSelector”的任何变体调用,因为所有带参数的变体都只接受对象参数。
这里的选择器将是“doSomethingWithMyAge:”,但任何尝试
[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];
根本不会编译。传递 NSNumber:@(42) 而不是 42,也无济于事,因为该方法需要一个基本的 C 类型——而不是对象。
此外,performSelector 变体最多有 2 个参数,仅此而已。虽然方法很多时候有更多的参数。
我发现虽然 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;
(是的,我从几个 Foundation 类类别中收集它们,例如 NSThread、NSRunLoop 和 NSObject)
每个变体都有自己的特殊行为,但都有一些共同点(至少当 waitUntilDone 设置为 NO 时)。“performSelector”调用将立即返回,并且对象的消息只会在一段时间后放在当前的运行循环中。
由于延迟执行 - 选择器的方法自然没有返回值可用,因此所有这些异步变体中的 -(void) 返回值。
我希望我以某种方式涵盖了这个......
@ennukiller 很到位。基本上,当您不(通常不可能)知道编译代码时将调用的方法的名称时,动态生成的选择器很有用。
一个关键的区别是-performSelector:
和朋友(包括多线程和延迟变体)有些限制,因为它们被设计用于具有 0-2 个参数的方法。例如,-outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:
使用 6 个参数调用并返回NSString
非常笨拙,并且提供的方法不支持。
选择器有点像其他语言中的函数指针。当您在编译时不知道要在运行时调用哪个方法时,可以使用它们。此外,与函数指针一样,它们仅封装了调用的动词部分。如果方法有参数,你也需要传递它们。
AnNSInvocation
具有类似的目的,只是它将更多信息绑定在一起。它不仅包括动词部分,还包括目标对象和参数。当您想用特定参数调用特定对象的方法时,这很有用,不是现在而是将来。您可以构建一个适当的NSInvocation
并在以后触发它。
两者之间还有另一个微妙的区别。
[object doSomething]; // is executed right away
[object performSelector:@selector(doSomething)]; // gets executed at the next runloop
这是Apple文档的摘录
“performSelector:withObject:afterDelay:在下一个运行循环周期和一个可选的延迟周期之后在当前线程上执行指定的选择器。因为它等到下一个运行循环周期执行选择器,这些方法提供了一个自动的迷你延迟当前执行的代码。多个排队的选择器按照它们排队的顺序一个接一个地执行。