117

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];
Keavon
  • 6,837
  • 9
  • 51
  • 79
TheGambler
  • 3,711
  • 5
  • 38
  • 54

5 Answers5

194

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.

bbum
  • 162,346
  • 23
  • 271
  • 359
ennuikiller
  • 46,381
  • 14
  • 112
  • 137
  • 3
    It's worth pointing out that you would actually assign the result of findTheAppropriateSelectorForTheCurrentSituation() to aSelector, then invoke [anObject performSelector:aSelector]. @selector produces a SEL. – Daniel Yankowsky Sep 29 '09 at 16:59
  • 4
    Using `performSelector:` is something you probably only do if you implement target-action in your class. The siblings `performSelectorInBackground:withObject:` and `performSelectorOnMainThread:withObject:waitUntilDone:` are often more useful. For spawning a background thread, and for calling back results to the main thread from said background thread. – PeyloW Sep 30 '09 at 08:36
  • 2
    `performSelector` is also useful to suppress compile warnings. If you know the method exists (like after using `respondsToSelector`), it will stop Xcode from saying "may not respond to `your_selector`". Just don't use it _instead_ of finding out the real cause of the warning. ;) – Marc Jun 21 '12 at 23:12
  • I read on some other thread on StackOverflow that use of performSelector was a reflection of a horrible design, and it had tons of thumbs up. I wish I could find it again. I searched google, restricting results to stackoverflow, and got 18,000 results. Eww. – Logicsaurus Rex Sep 09 '15 at 23:26
  • "reflection of a horrible design" is overly simplistic. This was what we had before blocks were available, and not all uses are bad, then or now. Although now that blocks _are_ available, that's probably a better choice for new code unless you are doing something very simple. – Ethan Apr 08 '16 at 22:36
  • performSelector lets you glimpse under the hood, and understand how ObjC messages are handled. The selector is actually a null terminated C string, which serves as a key string obj-C assigns to some method implementation (which is actually an IMPL - a C function). I've been using performSelector in many places, and it is GOOD. – Motti Shneor Jun 03 '19 at 15:14
  • One nice use of performSelector, is for sending a message without #import the header of the receiver. This way, you can decouple sources, and make some publicly available, without carrying #imports of other classes. – Motti Shneor Jun 03 '19 at 15:15
17

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

Motti Shneor
  • 2,095
  • 1
  • 18
  • 24
12

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

Quinn Taylor
  • 44,553
  • 16
  • 113
  • 131
  • 5
    To do that, you'd need to use an `NSInvocation` object. – Dave DeLong Sep 29 '09 at 16:02
  • 6
    Another difference: `performSelector:` and friends all take object arguments, meaning you can't use them to call (for example) `setAlphaValue:`, because its argument is a float. – Chuck Sep 29 '09 at 17:11
4

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.

Daniel Yankowsky
  • 6,956
  • 1
  • 35
  • 39
  • 5
    Selectors really aren't at all like a function pointer in that a function pointer is something you can call with arguments and a selector can be used to call a particular method on any object that implements it; a selector does not have the full context of invocation like a function pointer. – bbum Sep 29 '09 at 18:26
  • 1
    Selectors aren't the same as function pointers, but I still think they are similar. They represent verbs. C function pointers also represent verbs. Neither is useful without additional context. Selectors require an object and parameters; function pointers require parameters (which might include an object upon which to operate). My point was to highlight how they are different from NSInvocation objects, which do contain all the necessary context. Perhaps my comparison was confusing, in which case I apologize. – Daniel Yankowsky Oct 01 '09 at 07:15
  • 1
    Selectors aren't function pointers. Not even close. They are simple C strings in reality, that contain a "name" of a method (as opposed to 'function'). They're not even method signatures, because they do not embed the types of parameters. An object can have more than one method for the same selector (different param types, or different return type). – Motti Shneor Aug 03 '14 at 12:02
-8

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

avi
  • 57
  • 1
  • 7
  • 2
    Your answer is factually incorrect. The documentation you quote is about `performSelector:withObject:afterDelay:`, but the question and your snippet are using [`performSelector:`](http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/doc/uid/20000052-BBCBGHFG), which is an entirely different method. From the docs for it: The `performSelector:` method is equivalent to sending an `aSelector` message directly to the receiver. – jscs Nov 05 '11 at 18:48
  • 3
    thanks Josh for the clarification. You are correct; I thought `performSelector/performSelector:withObject/performSelector:withObject:afterDelay` all behaved the same way which was a mistake. – avi Nov 05 '11 at 20:50