使用-performSelector:与仅调用方法

The*_*ler 114 dynamic-languages objective-c selector method-dispatch

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

[object performSelector:@selector(doSomething)]; 

[object doSomething];
Run Code Online (Sandbox Code Playgroud)

enn*_*ler 191

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

因此即使这些是等价的:

[anObject aMethod]; 
[anObject performSelector:@selector(aMethod)]; 
Run Code Online (Sandbox Code Playgroud)

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

SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];
Run Code Online (Sandbox Code Playgroud)

在发送邮件之前.

  • 使用`performSelector:`是你可能只在你的类中实现target-action时才会做的事情.兄弟姐妹`performSelectorInBackground:withObject:`和`performSelectorOnMainThread:withObject:waitUntilDone:`通常更有用.用于生成后台线程,以及用于从所述后台线程向主线程调用结果. (4认同)
  • 值得指出的是,您实际上会将findTheAppropriateSelectorForTheCurrentSituation()的结果赋给aSelector,然后调用[anObject performSelector:aSelector].@selector生成一个SEL. (3认同)
  • “ performSelector”对于抑制编译警告也很有用。如果您知道该方法存在(例如在使用`respondsToSelector`之后),它将阻止Xcode说“可能不响应`your_selector`”。只是不要用它代替来找出警告的真正原因。;) (2认同)

Mot*_*eor 15

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

[object doSomething];
[object performSelector:@selector(doSomething)]; 
Run Code Online (Sandbox Code Playgroud)

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

这有点复杂,比如:

(void)doSomethingWithMyAge:(NSUInteger)age;
Run Code Online (Sandbox Code Playgroud)

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

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

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

[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];  
Run Code Online (Sandbox Code Playgroud)

根本就不会编译.传递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;
Run Code Online (Sandbox Code Playgroud)

总是返回一个对象,我能够返回一个简单的BOOL或NSUInteger,并且它有效.

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

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

另一个用途是异步地将消息分派给对象,稍后将在当前的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;
Run Code Online (Sandbox Code Playgroud)

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

每个变体都有自己的特殊行为,但都共享一些共同点(至少当waitUntilDone设置为NO时)."performSelector"调用将立即返回,并且对象的消息将在一段时间后才会被放在当前的runloop上.

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

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


Qui*_*lor 12

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

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

  • 另一个区别是:`performSelector:`和朋友都接受对象参数,这意味着你不能用它们来调用(例如)`setAlphaValue:`,因为它的参数是一个浮点数. (6认同)
  • 为此,您需要使用`NSInvocation`对象. (5认同)