Let's say I have a method called foo. What's the difference between:
[self foo];
and
[self performSelector:#selector(foo)];
Are they the same? The first one seems so much easier, so why would you ever want to use the second one?
From the docs:
The performSelector: method is equivalent to sending an aSelector message directly to the receiver. For example, all three of the following messages do the same thing:
id myClone = [anObject copy];
id myClone = [anObject performSelector:#selector(copy)];
id myClone = [anObject performSelector:sel_getUid("copy")];
However, the performSelector: method allows you to send messages that aren’t determined until runtime. A variable selector can be passed as the argument:
SEL myMethod = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector:myMethod];
Well, say you were getting a SEL from somewhere else, and you just wanted to execute it, you'd use this method.
Otherwise, yeah, you'd usually want to use the first example.
The first sends a message to an object and so does the second. In almost all cases, you should use the first. It's quicker and clearer. However, the second has its uses. For instance, you can use it in a situation where you would need to supply a call back.
Another powerful use is in combination with NSSelectorFromString(). You can literally decide what message to use at run time based on a string in a configuration file or from user input (don't forget to validate it!). You can even build selector names using NSString -stringWithFormat: etc. For instance, this parser kit uses the technique to inform the program when parser rules have been matched.
Related
suppose i call with
[self methodname]
and other with
[self performSelector:#selector(methodname) withObject:nil];
No difference whatsoever.
Straight from the documentation of performSelector:
The performSelector: method is equivalent to sending an aSelector message directly to the receiver. For example, all three of the following messages do the same thing:
id myClone = [anObject copy];
id myClone = [anObject performSelector:#selector(copy)];
id myClone = [anObject performSelector:sel_getUid("copy")];
While there's no difference in the specific case, however, the reason why performSelector: exists is that it allows invoking an arbitrary selector that may not be available at compile time, as discussed in the doc:
However, the performSelector: method allows you to send messages that aren’t determined until runtime. A variable selector can be passed as the argument:
SEL myMethod = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector:myMethod];
The considerations above also apply to the two variants performSelector:withObject:, performSelector:withObject:withObject:.
Please also note that this doesn't hold true for another set of methods, namely
performSelector:withObject:afterDelay:
performSelector:withObject:afterDelay:inModes:
performSelectorOnMainThread:withObject:waitUntilDone:
performSelectorOnMainThread:withObject:waitUntilDone:modes:
performSelector:onThread:withObject:waitUntilDone:
performSelector:onThread:withObject:waitUntilDone:modes:
performSelectorInBackground:withObject:
Further info here: Does performSelector perform right away or is it scheduled to be performed?
[self methodname]` is shorter and easier to read, write and comprehend.
[self performSelector:#selector(methodname) withObject:nil]` makes it possible to execute arbitrary selectors. If you save the selector in a variable, then you can execute it later on without knowing the method you invoke.
//Self works like this in oops and self works as setter for your class. It also indicates that u r using getter and setter method.
I'm new to Objective-C, but please help me out here.
What I'm seeing is that method signatures in Objective-C that take multiple parameters seem inconsistent.
Example:
- (void) sendEmail: (NSString *) toStr
subject:(NSString *) subjectStr
body:(NSString *) bodyStr;
OK, so here we have 3 "parameters" (at least that's what I'm used to calling them), but 2 of them have "external" names (subject, body) but the first one doesn't! Isn't there something wrong with that from a consistency/style point of view?
When we call this method we do it like:
[emailObj sendEmail:#"test#test.com" subject:#"testSub" body:#"this is a test"]
(Hopefully I did that right, remember I'm new to this.)
So the subject and the body are clearly marked in the call, but not the "to" address? It seems really wacked to me. Why is that first parameter getting special treatment?
I guess you thought that in the method declaration
-(void) A:(NSObject*)a B:(NSObject*)b C:(NSObject*)c
A is the method name, B and C are the names of parameters.
In Objective-C, the totality A:B:C: is the method name (more technically, called the selector) and used as a unit when you call a method by name. For example,
if([obj respondsToSelector:#selector(A:B:C:)]){
...
}
checks if obj responds to A:B:C:. But [obj respondsToSelector:#selector(A:)] will be NO in this case.
So, you should really think of the totality of A:B:C: as the method name, and A is the name of the first parameter.
Note also that you can't call A:B:C: as A:C:B:, either.
In most cases, methods like this are normally named so that the lack of a name on the first parameter makes sense. In this case, I would expect something like sendEmailTo.
I would say that if you're confused about what a method does, then it's probably not named as well as it could've been.
Given the selector above, I would expect the 3 parameters to be some sort of email object, a subject, and a body. Since, however, the first parameter is not an "Email" object but rather the recipient of an email, I would probably rename this method to be:
- (void) sendEmailToRecipient:(NSString *)recipient subject:(NSString *)subject body:(NSString *)body;
Is it possible to use #selector and performSelector: (or similar) with methods using variable arguments list?
I'm writing a class that can be assigned a delegate to override the default behavior. In the presence of a delegate select method calls made on an instance of that class will be forward to the same corresponding delegate method, some which use variable argument lists.
So, for instance, I need to be able to create retrieve SEL reference and message the delegate object with a method such as this:
- (void)logEventWithFormat:(NSString *)format, ... {
va_list argList;
id del = self.delegate;
if (del != nil &&
[del conformsToProtocol:#protocol(AProtocolWithOptionalMethods)] &&
[del respondsToSelector:#selector(logEventWithFormat:)])
{
// Perform selector on object 'del' with 'argList'
}
}
I am assuming this is not possible, hence the similar method declaration in the Foundation framework - in NSString:
- (id)initWithFormat:(NSString*)format, ...;
and
- (id)initWithFormat:(NSString *)format arguments:(va_list)argList;
I assume that the protocol I wish to delegate to should suggest the implementation of:
- (void)logEventWithFormat:(NSString *)format arguments:(va_list)argList;
so I the selector #selector(logEventWithFormat:arguments:) can be used an called with:
[del performSelector:#selector(logEventWithFormat:arguments:)
withObject:format
withObject:argList];
I just wondered if I was missing something or going the long way around to achieve what I'm trying to?
You can pass anything you want into the runtime function objc_msgSend.
objc_msgSend(del, #selector(logEventWithFormat:arguments:), format, argList);
It's the most powerful way of sending a manually constructed message.
However, it's not clear that you need to perform the invocation this way. As KennyTM pointed out, in the code you have, you could invoke the method directly.
You can't use -performSelector:withObject:withObject: because va_list simply isn't an "object". You need to use NSInvocation.
Or simply call
[del logEventWithFormat:format arguments:argList];
As far as I know, it can't be done. You can't use -performSelector:withObject:withObject: because as #KennyTM points out, a va_list isn't an object.
However, you also cannot use NSInvocation. The documentation straight up says so:
NSInvocation does not support
invocations of methods with either
variable numbers of arguments or union
arguments.
Since these are the two ways of invoking a method by selector, and neither seems to work, I'm going to go with the "can't be done" answer, unless you invoke the method directly and pass the va_list as an argument.
Perhaps #bbum will show up and enlighten us further. =)
I haven't done it that way before, but the simple solution I've often used is to box/unbox either an NSMutableArray or an NSMutableDictionary for the withObject parameter.
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];
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.
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...
#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.
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.
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."
First, I'm not sure I really understand what a selector is. From my understanding, it's the name of a method, and you can assign it to a class of type 'SEL' and then run methods such as respondToSelector to see if the receiver implements that method. Can someone offer up a better explanation?
Secondly, to this point, I have the following code:
NSString *thing = #"Hello, this is Craig";
SEL sel = #selector(lowercaseString:);
NSString *lower = (([thing respondsToSelector:sel]) ? #"YES" : #"NO");
NSLog (#"Responds to lowercaseString: %#", lower);
if ([thing respondsToSelector:sel]) //(lower == #"YES")
NSLog(#"lowercaseString is: %#", [thing lowercaseString]);
However, even though thing is clearly a kind of NSString, and should respond to lowercaseString, I cannot get the 'respondsToSelector' conditional to return "YES"...
You have to be very careful about the method names. In this case, the method name is just "lowercaseString", not "lowercaseString:" (note the absence of the colon). That's why you're getting NO returned, because NSString objects respond to the lowercaseString message but not the lowercaseString: message.
How do you know when to add a colon? You add a colon to the message name if you would add a colon when calling it, which happens if it takes one argument. If it takes zero arguments (as is the case with lowercaseString), then there is no colon. If it takes more than one argument, you have to add the extra argument names along with their colons, as in compare:options:range:locale:.
You can also look at the documentation and note the presence or absence of a trailing colon.
Selectors are an efficient way to reference methods directly in compiled code - the compiler is what actually assigns the value to a SEL.
Other have already covered the second part of your q, the ':' at the end matches a different signature than what you're looking for (in this case that signature doesn't exist).
That's because you want #selector(lowercaseString), not #selector(lowercaseString:). There's a subtle difference: the second one implies a parameter (note the colon at the end), but - [NSString lowercaseString] does not take a parameter.
In this case, the name of the selector is wrong. The colon here is part of the method signature; it means that the method takes one argument. I believe that you want
SEL sel = #selector(lowercaseString);
NSString's method is lowercaseString (0 arguments), not lowercaseString: (1 argument).
Don't think of the colon as part of the function name, think of it as a separator, if you don't have anything to separate (no value to go with the function) then you don't need it.
I'm not sure why but all this OO stuff seems to be foreign to Apple developers. I would strongly suggest grabbing Visual Studio Express and playing around with that too. Not because one is better than the other, just it's a good way to look at the design issues and ways of thinking.
Like
introspection = reflection
+ before functions/properties = static
- = instance level
It's always good to look at a problem in different ways and programming is the ultimate puzzle.
From my understanding of the Apple documentation, a selector represents the name of the method that you want to call. The nice thing about selectors is you can use them in cases where the exact method to be called varies. As a simple example, you can do something like:
SEL selec;
if (a == b) {
selec = #selector(method1)
}
else
{
selec = #selector(method2)
};
[self performSelector:selec];
As per apple docs:
https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Selector.html
A selector is the name used to select a method to execute for an object, or the unique identifier that replaces the name when the source code is compiled. A selector by itself doesn’t do anything. It simply identifies a method. The only thing that makes the selector method name different from a plain string is that the compiler makes sure that selectors are unique. What makes a selector useful is that (in conjunction with the runtime) it acts like a dynamic function pointer that, for a given name, automatically points to the implementation of a method appropriate for whichever class it’s used with. Suppose you had a selector for the method run, and classes Dog, Athlete, and ComputerSimulation (each of which implemented a method run). The selector could be used with an instance of each of the classes to invoke its run method—even though the implementation might be different for each.
Example:
(lldb) breakpoint --set selector viewDidLoad
This will set a breakpoint on all viewDidLoad implementations in your app.
So selector is kind of a global identifier for a method.