Runtime series
Layman Runtime (a): acquaintance
layman Runtime (2): The data structure
layman Runtime (III): messaging
layman Runtime (IV): The nature of super
layman Runtime (e): a particular application
layman Runtime (VI): interview questions related
1. objc_super 与 objc_msgSendSuper
Let's look at two data structures objc_super
and objc_super2
.
They can see that the difference between the two is that the second member:
objc_super
: // super_class ReceiverClass parent
objc_super2
: current_class // receiverClass (class object message recipient)
// message.h(objc4)
struct objc_super {
__unsafe_unretained _Nonnull id receiver; // 消息接收者
#if !defined(__cplusplus) && !__OBJC2__
/* For compatibility with old objc-runtime.h header */
__unsafe_unretained _Nonnull Class class;
#else
__unsafe_unretained _Nonnull Class super_class; // receiverClass 的父类
#endif
/* super_class is the first class to search */
};
// objc_runtime_new.h(objc4)
struct objc_super2 {
id receiver; // 消息接收者
Class current_class; // receiverClass(消息接收者的class对象)
};
Let's look at two functions objc_msgSendSuper()
and objc_msgSendSuper2()
.
From the source point of view, two function parameters received no difference,
but we can surmise from official comments, objc_msgSendSuper2()
the first argument should be received objc_super2
instead objc_super
.
// message.h(objc4)
void objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )
// objc-abi.h(objc4)
// objc_msgSendSuper2() takes the current search class, not its superclass.
id _Nullable objc_msgSendSuper2(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
2. self and super
self
- OC implicit methods with two parameters:
(id)self
and(SEL)_cmd
; - the object is a self pointer to the current method caller / recipient of the message;
if instance method, it is the object points to the current instance of the class;
if it is a class method, which points to the class object is the current class. - When using self calling a method, the bottom will be converted to
objc_msgSend()
the calling function, can know through the article, the function will search from the current implementation of the message recipient class.
super
- It is a super compiler directives;
- When using super call method, the underlying converted to
objc_msgSendSuper2()
the calling function, the function will search from the current implementation of the message receiver parent class.
3. super nature
We clang convert the OC code for the C ++ code:
[super viewDidLoad];
// 转换为 C++
((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("viewDidLoad"));
// 简化
struct objc_super arg = {
self,
class_getSuperclass(objc_getClass("ViewController"))
};
objc_msgSendSuper(arg, sel_registerName("viewDidLoad"));
You can see, Runtime will be super
converted to a objc_msgSendSuper()
function call, parameters objc_super
and SEL
.
Intermediate code LLVM &
So why said earlier super
converted to objc_msgSendSuper2()
call the function of it?
Because the real implementation and the underlying turn into C ++ implementation is different,
LLVM
the compiler will "-OC Code" to turn into "intermediate code (.ll)" then into "assembler, machine code", the intermediate code is non- C / C ++.
You can use the following command line instruction generating intermediate code: clang -emit-llvm -S main.m
details, refer to the official documentation LLVM , do not make too much introduction.
By compiling verification
ViewController.m converting files into assembly code to verify:
see line 18 of code that is [super viewDidLoad]
converted into assembly code
You can see above, [super viewDidLoad]
the underlying fact is converted into objc_msgSendSuper2()
function calls instead objc_msgSendSuper()
.
super nature
- When using super call method, the underlying converted to
objc_msgSendSuper2()
call the function, the function takes two parametersstruct objc_super2
andSEL
.
struct objc_super2 {
id receiver; // 消息接收者
Class current_class; // receiverClass
};
id _Nullable objc_msgSendSuper2(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
objc_msgSendSuper2()
Internally by the functioncurrent_class
of thesuperclass
pointer to get its parent class, from the beginning to find the parent class implementation of the method. Ignore "Find method from receiverClass procedure", the corresponding figure is started from step 5.
- 要注意
receiver
消息接收者还是子类对象,而不是父类对象,只是查找方法实现的范围变了。
4. 相关面试题
Q:调用以下 init 方法的打印结果是什么?
@interface HTPerson : NSObject
@end
@interface HTStudent : HTPerson
@end
@implementation HTStudent
- (instancetype)init
{
if (self = [super init]) {
NSLog(@"[self class] = %@",[self class]);
NSLog(@"[super class] = %@",[super class]);
NSLog(@"[self superclass] = %@",[self superclass]);
NSLog(@"[super superclass] = %@",[super superclass]);
}
return self;
}
@end
[self class] = HTStudent
[super class] = HTStudent
[self superclass] = HTPerson
[super superclass] = HTPerson
class
和superclass
方法的实现在 NSObject 类中,可以看到它们的返回值取决于receiver
。
+ (Class)class {
return self;
}
- (Class)class {
return object_getClass(self);
}
+ (Class)superclass {
return self->superclass;
}
- (Class)superclass {
return [self class]->superclass;
}
[self class]
是从receiverClass
开始查找方法的实现,如果没有重写的情况,则会一直找到基类 NSObject,然后调用。
[super class]
是从receiverClass->superclass
开始查找方法的实现,如果没有重写的情况,则会一直找到基类 NSObject,然后调用。
由于receiver
相同,所以它们的返回值是一样的。