Using -performSelector: vs. just calling the method
Solution 1
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.
Solution 2
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...
Solution 3
@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.
Solution 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.
Related videos on Youtube
TheGambler
Updated on July 08, 2022Comments
-
TheGambler almost 2 years
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];
-
Dave DeLong over 14 yearsTo do that, you'd need to use an
NSInvocation
object. -
Daniel Yankowsky over 14 yearsIt's worth pointing out that you would actually assign the result of findTheAppropriateSelectorForTheCurrentSituation() to aSelector, then invoke [anObject performSelector:aSelector]. @selector produces a SEL.
-
Chuck over 14 yearsAnother 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. -
bbum over 14 yearsSelectors 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.
-
PeyloW over 14 yearsUsing
performSelector:
is something you probably only do if you implement target-action in your class. The siblingsperformSelectorInBackground:withObject:
andperformSelectorOnMainThread:withObject:waitUntilDone:
are often more useful. For spawning a background thread, and for calling back results to the main thread from said background thread. -
Daniel Yankowsky over 14 yearsSelectors 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.
-
jscs over 12 yearsYour answer is factually incorrect. The documentation you quote is about
performSelector:withObject:afterDelay:
, but the question and your snippet are usingperformSelector:
, which is an entirely different method. From the docs for it: <quote>TheperformSelector:
method is equivalent to sending anaSelector
message directly to the receiver.</quote> -
avi over 12 yearsthanks Josh for the clarification. You are correct; I thought
performSelector/performSelector:withObject/performSelector:withObject:afterDelay
all behaved the same way which was a mistake. -
Marc about 12 years
performSelector
is also useful to suppress compile warnings. If you know the method exists (like after usingrespondsToSelector
), it will stop Xcode from saying "may not respond toyour_selector
". Just don't use it instead of finding out the real cause of the warning. ;) -
Motti Shneor almost 10 yearsSelectors 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).
-
Logicsaurus Rex almost 9 yearsI 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.
-
Ethan about 8 years"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.
-
Motti Shneor about 5 yearsperformSelector 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 about 5 yearsOne 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.