Why are warnings generated when calling methods undeclared in a class interface using conventional means, but not when calling methods using @selector? Is it because selectors can be executed by a different caller than self?
For example:
-(void) doStuff
{
[self doNow]; // Warning: instance method not found
SEL sel = @selector(doNow); // no warnings
}
-(void) doNow {} // this method is not declared in the interface
The "Undeclared Selector" warning is turned off by default. I don't know why. You can turn it back on in the Build Settings.
The documentation for this settings reads:
Warn if a "@selector(...)" expression referring to an undeclared selector is found. A selector is considered undeclared if no method with that name has been declared before the "@selector(...)" expression, either explicitly in an @interface or @protocol declaration, or implicitly in an @implementation section. This option always performs its checks as soon as a "@selector(...)" expression is found, while -Wselector only performs its checks in the final stage of compilation. This also enforces the coding style convention that methods and selectors must be declared before being used. [GCC_WARN_UNDECLARED_SELECTOR, -Wundeclared-selector]
A similar question was asked on SO a few weeks ago.
This is basically because selectors are late-bound. They're not looked up until runtime. There are options for forcing verification during compilation. The question I linked to has some more information on how you can do that.
The way @selector works by default is you are telling the compiler; trust me I have this method somewhere in my class. Its the same concept if you do @class yourclassname instead of importing the .h file which contains the class.
This is because the compiler needs to know the signature of the method in order to call it (i.e. [self doNow];
), because such a call translates to either a call to objc_msgSend
or objc_msgSend_stret
depending on whether the method signature has a return type of a struct
or not. (Remember the difference between the selector (simply the name with the colons in it, but with no types) and the signature (the types) of a method.) So it needs to warn because it could be calling the wrong function if it doesn't know.
However, just getting a selector (@selector(...)
), it doesn't need to know the types. The selector is simply a name, and you've provided the name. It's all about what you use the selector for. If you use it in performSelector:
, it also doesn't need to know the types, because that method only works for methods with argument and return types of objects, so there is no ambiguity. Hence there is no need for a warning.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With