What does the compiler do when it finds [super msg];

I read the chapter "messaging" with programming with objective c and got some questions about myself and super. AFAIK, when the compiler finds a message, it translates it into objc_msgSend with two hidden parameters - receiver, selector and argument variables for the selector. for example [self test] would be something like this:

 objc_msgSend(self, @selector(test)); 

if there is no method implementation in the receiver manager table, then the function will try to find the implementation in superclasses. super is just a flag for the compiler to start implementing the search method in the superclass of the current object, and in the documentation apple says that when the compiler finds "super", it translates it something like this:

 struct objc_super mySuperClass = { self, [self superclass] }; objc_msgSendSuper(&mySuperClass, @selector(forwardedMethod)); 

I created a project with 3 classes, each of which inherits from the other.

 @interface FirstClass : NSObject - (void)forwardMethod; @end @interface SecondClass : FirstClass @end @interface ThirdClass : SecondClass @end 

I instantiated a third class in my root view controller and called its method called 'forwardMethod'. Implementation:

 //First Class - (void)forwardMethod { NSLog(@"Base class reached"); } //SecondClass imp - (void)forwardMethod { NSLog(@"second class"); [super forwardMethod]; } //ThirdClass imp - (void)forwardMethod { NSLog(@"third class"); [super forwardMethod]; } 

Everything works perfectly. But then I decided to interpret the compiler:

 //First Class - (void)forwardMethod { NSLog(@"Base class reached"); } //SecondClass imp - (void)forwardMethod { NSLog(@"second class"); struct objc_super mySuperClass = { self, [self superclass] }; objc_msgSendSuper(&mySuperClass, @selector(forwardMethod)); } //ThirdClass imp - (void)forwardMethod { NSLog(@"third class"); struct objc_super mySuperClass = { self, [self superclass] }; objc_msgSendSuper(&mySuperClass, @selector(forwardMethod)); } 

The result is a recursive call to the second class 'forwardMethod'. I create a structure in 'forwardMethod' in the second class using self and [self supererclass], but self is the third class and
my superclass will always be "second class". Maybe I'm doing something wrong, but how can I go to the base class 'forward method'?

+6
source share
2 answers

Note. For educational purposes only (that's good!), Do not use in production code!

You are also there, just one class ...

To find out why you get recursion, consider how a superclass can be found using information available at compile time and at run time.

At run time, the value of self is a reference to the current object, you can use self to search for the class of the object - in your example, self is an object of type ThirdClass .

Now the value of self does not change as you call methods, so in your example, even in FirstClass forwardMethod value of self is a reference to an object of type ThirdClass . Thus, self allows you to find the type of an object, but it does not tell you where you are currently executing the method in its inheritance chain, therefore, by itself, it cannot tell you what the next class is in this chain.

Therefore, consider compilation time. When compiling SecondClass compiler knows that the superclass is FirstClass , so calling super is a method call in FirstClass (except for the caveat below). Thus, the compiler can use self and [FirstClass class] to determine the runtime object for which to call the method and the compile time class from which to start searching for the method (since the search for any method is a search starting from the class and starting from inheritance chain until an implementation is found). So, in your code example, you were only one way:

 @implementation SecondClass - (void)forwardMethod { NSLog(@"second class"); struct objc_super mySuperClass = { self, [FirstClass class] }; objc_msgSendSuper(&mySuperClass, @selector(forwardMethod)); } 

If you use this, the code will work. But...

... this is the warning mentioned above. Objective-C allows you to change the inheritance chain at runtime using the swizzling class, so the compiler cannot rely on the whole compilation-time inheritance chain to develop a superclass. So what can he use? Well, when compiling a source for a particular method, it knows the class to which this method belongs, so it can compile this class of methods into code to find the superclass and use the code that starts the method search in the next class by inheritance execution time. This is what the compiler will do for your code, just in case you used the swizzling class:

 @implementation SecondClass - (void)forwardMethod { NSLog(@"second class"); struct objc_super mySuperClass = { self, [SecondClass class] }; objc_msgSendSuper2(&mySuperClass, @selector(forwardMethod)); } 

Note that the compiler passes the current compilation time class ( [SecondClass class] ) and calls objc_msgSendSuper2 to search - which will find the first method in the run-time inheritance chain, which is after SecondClass m, whereas `objc_msgSendSuper will start the search in SecondClass yourself.

Good luck, but don't use this in general code (unless you have a very, very, very ... very good reason;))

+6
source

In your SecondClass, this structure will be filled with exactly the same contents as your ThirdClass:

  struct objc_super mySuperClass = { self, [self superclass] }; 

self has the same meaning in both cases, and thus [self superclass] will always be SecondClass when called from an instance of ThirdClass (even if the actual implementation — the code — is in SecondClass). There is a bit more magic to what the compiler emits (objc_msgSendSuper is pretty simple) that it should emit a reference to the class, so even things like setting and / or isa manipulation pointer is a bad programmer, without a donut - still work , as was expected. I did not look into the details for a long time to know exactly how it works.

Source for runtime and compiler available.

+4
source

Source: https://habr.com/ru/post/948429/


All Articles