The difference between [self class] and [super class] in the classic iOS explanation

Author: Loving_iOS
reprint http://blog.csdn.net/loving_ios/article/details/49884599
These two keywords "self" and "super" are often seen in the class implementation in objc, but their difference is in every aspect.
Take the following code as an example:

 view plain copy
@interface Father:NSObject   
{  
NSString*  name;  
}  
- (void)setName:(NSString*) yourName;  
@end  
@interface Son:Father  
{  
NSUInteger age;  
}  
- (void) setAge:(NSUInteger) age;  
- (void) setName:(NSString*) yourName andAge:(NSUInteger) age;  
@end  
@implementation Son  
- (void) setName:(NSString*) yourName andAge:(NSUInteger) age   
{  
[self setAge:age];  
[super setName:yourName];  
}  
@end  
int main(int argc, char* argv[]) {  
AutoreleasePool{  
Son* son = [[Son alloc] init];  
[son setName:@"aaa" andAge:18];    
}  
return 0;  
}  

There are two simple classes above. The subclass Son calls setAge in its own class and setName in the parent class. These codes seem to be well understood and there is no problem. Then I add two lines to the method of setName:andAge:
NSLog(@"self ' class is %@", [self class]);
NSLog(@"super' class is %@", [super class]);

In this way, when the call is made, the two classes will be typed out. Guess first, what will be printed out? According to the previous experience of oop language, this should output: self ' s class is Son super ' s class is Father

But after compiling and running, you can find that the result is:

self ‘s class is Son

super ’ s class is Son

The class of self is the same as expected, so why is the class of super also Son?

The specific reason depends on what their internal implementation mechanism is:

self is a hidden parameter of the class, pointing to the class that is currently calling the method. Another hidden parameter is _cmd, which represents the selector of the current class method. Only focus on this self here. what is super? super is not a hidden parameter, it is just a "compiler indicator", it points to the same message receiver as self, take the above code as an example, whether it is [self setName] or [super setName], receive The receiver of the "setName" message is the son object. The difference is that super tells the compiler that when the method of setName is called, it should call the method of the parent class, not the one in this class. The function of super is just an indicator and has no practical significance.

When using self to call a method, it will start looking from the method list of the current class, if not, it will look for it from the parent class; when using super, it will start looking from the method list of the parent class. Then call this method of the parent class.

How is this mechanism implemented at the bottom? In fact, when a class method is called, the compiler converts the method call into a C function method call. Apple's objcRuntimeRef says:

Sending Messages
When it encounters a method invocation, the compiler might generate a call to any of several functions to perform the actual message dispatch, depending on the receiver, the return value, and the arguments. You can use these functions to dynamically invoke methods from your own plain C code, or to use argument forms not permitted by NSObject’s perform… methods. These functions are declared in /usr/include/objc/objc-runtime.h.
■ objc_msgSend sends a message with a simple return value to an instance of a class.
■ objc_msgSend_stret sends a message with a data-structure return value to an instance of
a class.
■ objc_msgSendSuper sends a message with a simple return value to the superclass of an instance of a class.
■ objc_msgSendSuper_stret sends a message with a data-structure return value to the superclass of an instance of a class.

It can be seen that one of the above four methods will be called. Since the _stret series is similar to the two without _stret, only focus on the objc_msgSend and objc_msgSendSuper methods.

When using [self setName] to call, the function of objc_msgSend will be used, first look at the function definition of objc_msgSend:

id objc_msgSend(id theReceiver, SEL theSelector, …)

The first parameter is the message receiver, the second parameter is the selector of the specific class method to call, followed by the variable parameters of the selector method. Let's ignore this variable parameter first, take [self setName:] as an example, the compiler will replace it with a function call that calls objc_msgSend, where theReceiver is self, theSelector is @selector(setName:), this selector is the class from the current self The method list starts to look for the setName, and when it is found, the corresponding selector is passed to the past.

When using [super setName] to call, the objc_msgSendSuper function will be used, look at the function definition of objc_msgSendSuper:

id objc_msgSendSuper(struct objc_super *super, SEL op, …)

The first parameter is an objc_super structure, and the second parameter is a selector similar to the above class method. Let's first look at what the objc_super structure is:

struct objc_super {
id receiver;
Class superClass;
};

You can see that this structure contains two members, one is receiver, which is similar to the first parameter receiver of objc_msgSend above, and the second member is to record what the parent class of the super class is. Take the above code as an example, When the compiler encounters the [super setName:] in the setName:andAge method in Son, it starts doing the following:

1. Build the structure of objc_super. At this time, the first member variable receiver of this structure is son, which is the same as self. The second member variable superClass refers to the class Father, because Son's superclass is this Father.

2. Call the method of objc_msgSendSuper and pass this structure and the sel of setName. What the function is doing is similar to this: starting from the method list of the superClass pointed to by the objc_super structure, find the selector of setName, and then call the selector with objc_super->receiver, and may also use the objc_msgSend function, but at this time The first parameter theReceiver is objc_super->receiver, the second parameter is the selector found from objc_super->superClass

The calling mechanism inside is generally like this. Based on the above analysis, looking back at the starting code, what kind of process is it when [self class] and [super class] are output.

When using [self class], the self at this time is Son. When using objc_msgSend, the first parameter is the receiver, which is self, which is also an instance of Son* son. For the second parameter, you must first find the selector of the class method, first start with the Son class, no, then go to Son's parent class Father, and no, then go to Father's parent class NSObject to find it, a layer After looking up one level, the class method is found in the NSObject class, and the class method of NSObject returns the category of the receiver, so Son is output here.

When using [super class], it should be converted to the method of objc_msgSendSuper. First construct the structure of objc_super, the first member variable is self, the second member variable is Father, and then to find the selector of class, first go to superClass, which is Father, to find it, no, then go to the parent class of Father Looking for it, the result is still found in NSObject. Then use the function objc_msgSend(objc_super->receiver, @selector(class)) to call it internally, which is the same as when we called it with [self class]. The receiver at this time is still Son* son, so what is returned here is also Son .

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325609325&siteId=291194637