Following is a snippet from a View Controller's implementation:
- (void)myOtherAwesomeMethod
{
[self myAwesomeMethod]; // Compile ERROR here: Receiver type for instance message does not declare a method with selector
}
- (void)myAwesomeMethod
{
NSLog(@"%@", @"Calling my awesome method...");
}
- (void)viewDidLoad
{
[self myAwesomeMethod];
[self myOtherAwesomeMethod];
}
I do not have myAwesomeMethod
method declared in my header file, but why is it that I can call myAwesomeMethod
in viewDidLoad
, but not in myOtherAwesomeMethod
?
I know the solution to this error is to declare the method in my header file, but I'd like to understand why this is happening.
In C, the rule is: you got to declare it before you use it.
Files are compiled from the top down. So here's what is happening in your code:
The compiler reads the @interface declaration for your class. Since you say neither method is declared in the header file, neither are in the symbol table yet.
Your symbol table contains: nothing yet
The compiler reads the method definition for myAwesomeMethod
. You haven't declared it yet, so it gets added to the symbol table. The body of the method contains a call to NSLog
, which was declared long ago in a header provided to you by Apple.
Your symbol table contains: myAwesomeMethod
The compiler reads the method definition for viewDidLoad
; it was actually declared in a superclass's header file. The body of the method contains a call to myAwesomeMethod
, which was found! It also contains a call to myOtherAwesomeMethod
. Never heard of it!
Now, this isn't an error, because it can still generate the code to make the call. It can infer argument types by how you use it (in this case, no arguments). It can't be sure of the return type, though (just because you don't use the return value doesn't mean there wasn't one). So it proceeds on the assumption that the call returns id
and generates a warning.
Your symbol table contains: myAwesomeMethod
Finally, the compiler reads the method definition for myOtherAwesomeMethod
. It gets added to the symbol table. It compiles the body, which contains a call to myAwesomeMethod
, which is in the table. All's well that ends well.
At the end of the file, your symbol table contains: myAwesomeMethod
, myOtherAwesomeMethod
If you're coming from a language like Java, this may seem silly, but that's because Java works differently than C. In Java, source code is compiled and linked in one step; you can't compile a class that refers to another class without having either the source code or class files available. That can be a hassle, but on the other hand, you never need about declarations apart from definitions.
In C, compiling and linking are different steps. The compiler just generates object code that refers to symbols that may be defined elsewhere; it uses declarations to make sure it generates the right code. The linker is responsible for matching up all those symbols with definitions in other libraries, static or dynamic.
In Objective-C, the linker doesn't actually know/care about Objective-C messages, because there is no way of knowing at compile-time/link-time whether an object can respond to a message. So it passes the buck to the runtime, which throws an exception if you get that far without a method definition.
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