preface
The source environment involved in this article is ObjC4-818.2
We’ve used self and super countless times in our initialization methods, so we’re going to look at them today.
- Create a class
Father
Inherited fromNSObject
- Create a class
Son
Inherited fromFather
@implementation Son -(instancetype)init{ if (self = [super init]) { NSLog(@"1 -- %@",[self class]); NSLog(@"2 -- %@",[super class]); } return self; } @end outputs 1 -- Son 2 -- SonCopy the code
1
Print out the currentSon
No problem, then why2
No outputSon
The parent classFather
????- why
[super init]
Return a subclass instance object instead of a superclass instance object.
self
See the implementation of the class method in the source environment’s nsobject.mm
- (Class)class { return object_getClass(self); } Class object_getClass(id obj) { if (obj) return obj->getIsa(); else return Nil; } Inline Class objc_object::getIsa() { isTaggedPointer())) return ISA(); . } inline Class objc_object::ISA(bool authenticated) { ASSERT(! isTaggedPointer()); return isa.getDecodedClass(authenticated); } inline Class isa_t::getDecodedClass(bool authenticated) { ... return getClass(authenticated); } inline Class isa_t::getClass(MAYBE_UNUSED_AUTHENTICATED_PARAM bool authenticated) { ... uintptr_t clsbits = bits; . clsbits &= ISA_MASK; . return (Class)clsbits; }Copy the code
The isa pointer to a nonpointer object contains a pointer to a class object.
We might be curious about the class method why isn’t self the object that he calls NSObject?
- (Class) Class {// who is self accessed here?? return object_getClass(self); }Copy the code
We know that the function is executed at the bottom of OC via objc_msgSend, which has two default arguments self and _cmd
self
For message receiver_cmd
For the function name.
And then parameters
id objc_msgSend(id self, SEL _cmd, ...) ;Copy the code
There are also default arguments self and _cmd in the function, which correspond to the default arguments in objc_msgSend and can be easily understood as
- (Class)class(id self, SEL _cmd) {
......
}
Copy the code
Because we don’t implement class methods in either Father or Son custom classes, the message lookup process looks up the inheritance chain to the class method in NSObject, but the self object is still an instance object of Son.
Let’s do one more little example of implementing the method fatherMethod in Father
@interface Father : NSObject
- (void)fatherMethod;
@end
@implementation Father
- (void)fatherMethod{
NSLog(@"self == %@",self);
}
@end
Copy the code
There are no methods implemented in subclass Son, so we call the fatherMethod method with the instance object of the subclass
int main(int argc, char * argv[]) {
@autoreleasepool {
Son *son = [[Son alloc] init];
[son fatherMethod];
}
return 0;
}
Copy the code
The execution result is
self == <Son: 0x28211c140>
Copy the code
No matter where the method is implemented, the self accessed in the method is the message receiver.
super
Self is the message receiver and is one of the default arguments to the message sending function objc_msgSend. Super is not so simple; it is not a parameter but a compiler keyword. We implement it in son.m
@implementation Son
-(instancetype)init{
if (self = [super init]) {
NSLog(@"%@",[super class]);
}
return self;
}
@end
Copy the code
We explore the underlying principles through clang and assembly
throughclang
Look at the underlying implementation
The terminal goes to the son. m path and runs the command
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Son.m
Copy the code
You can see that the underlying implementation of [super class] in son.cpp is
struct __rw_objc_super { struct objc_object *object; struct objc_object *superClass; __rw_objc_super(struct objc_object *o, struct objc_object *s) : object(o), superClass(s) {} }; . ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Son"))}, sel_registerName("class"))Copy the code
The message is sent through objc_msgSendSuper instead of objc_msgSend, and the message receiver becomes the __rw_objc_super structure pointer
Viewing by assembly
The difference here is that it’s executedobjc_msgSendSuper2
The source code to explore
We enter the lower world with these questions
objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
objc_msgSendSuper2(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
Copy the code
The arguments to both functions are the same, with two default arguments
objc_super
The type ofsuper
SEL
The type ofop
- The parameter
Objc_super structure is (objC2 environment)
struct objc_super {
__unsafe_unretained _Nonnull id receiver;
__unsafe_unretained _Nonnull Class super_class;
/* super_class is the first class to search */
};
Copy the code
Note that super_class is the first class to be searched when a method is searched
Search the objc_msgSendSuper and objc_msgSendSuper2 implementations in the objC-msG-arm64.s file
ENTRY _objc_msgSendSuper // Go to L_objc_msgSendSuper2_body and continue b L_objc_msgSendSuper2_body END_ENTRY _objc_msgSendSuper ENTRY _objc_msgSendSuper2 UNWIND _objc_msgSendSuper2, NoFrame // Unlike objc_msgSend, P16 does not point to class but to superclass LDP P0, p16, [x0] ldr p16, [x16, #SUPERCLASS] L_objc_msgSendSuper2_body: CacheLookup NORMAL, _objc_msgSendSuper2, __objc_msgSend_uncached END_ENTRY _objc_msgSendSuper2Copy the code
Unlike objc_msgSend, p16 does not point to class but to superclass, but the message receiver, receiver, is the same. Verify this.
Define and implement methods fatherMethod and method in the Father class
@interface Father : NSObject
- (void)fatherMethod;
- (void)method;
@end
@implementation Father
- (void)fatherMethod{
NSLog(@"self == %@",self);
}
- (void)method{
NSLog(@"father-method");
}
@end
Copy the code
Override the fatherMethod method in subclass Son and implement the method method
@interface Son : Father
- (void)method;
@end
@implementation Son
- (void)fatherMethod{
[super fatherMethod];
[super method];
}
- (void)method{
NSLog(@"son-method");
}
@end
Copy the code
run
int main(int argc, char * argv[]) { @autoreleasepool { Son *son = [[Son alloc] init]; [son fatherMethod]; } return 0; } self == <Son: 0x2806b8130> father-methodCopy the code
The message receiver in [super fatherMethod] is still an instance object of subclass Son, so self accessed from fatherMethod is an instance object of Son
Although subclass Son also implements method methods, [super method] is found from Father
summary
Self calls method [self XXX] and super calls method [super XXX]
- The similarities are as follows: Message receiver
receiver
Is the same - The differences are:
[super xxx]
The message lookup process starts with the parent class
-(instancetype)init{
if (self = [super init]) {
......
}
return self;
}
Copy the code
+ (id)init {
return (id)self;
}
Copy the code
[super init] looks for the init function from the parent class, but the message receiver is still a subclass instance object, so self called and returned in init is the subclass instance object.
Refer to the article
Self and super in # OC