[toc]
面试题
先切入一个面试问题, 下面代码会输出什么?
// Student: Person: NSObject
- (instancetype)init {
if (self = [super init]) {
NSLog(@"[self class] = %@", [self class]); // Student
NSLog(@"[self superclass] = %@", [self superclass]); // Person
NSLog(@"--------------------------------");
// objc_msgSendSuper({self, [Person class]}, @selector(class));
// ({消息接收者, 消息接收者父类}, SEL)
NSLog(@"[super class] = %@", [super class]); // Student
NSLog(@"[super superclass] = %@", [super superclass]); // Person
}
return self;
}
底层分析
OC代码
// Student: Person: NSObject
- (void)run {
[super run]; // super调用的消息接收者仍然是 self (Student实例)
}
转成C++代码
static void _I_Student_run(Student * self, SEL _cmd) {
((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("run"));
}
// objc4/message.h
id _Nullable objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
上面代码拆解
struct __rw_objc_super rcv = {
self,
class_getSuperclass(objc_getClass("Student"))
}
objc_msgSendSuper(rcv, @selector(run))
objc_super
__rw_objc_super
等价于 objc_super
// objc4/message.h
/// Specifies the superclass of an instance.
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained _Nonnull id receiver; // 消息接收者
__unsafe_unretained _Nonnull Class super_class; // 消息接收者的父类
/* super_class is the first class to search */
};
class_getSuperclass()
// objc4/runtime.h
Class _Nullable class_getSuperclass(Class _Nullable cls)
// objc4/objc-class.mm
Class class_getSuperclass(Class cls) {
if (!cls) return nil;
return cls->superclass;
}
objc_msgSendSuper()
可以看到, 使用 super 调用方法, 底层被转换成 objc_msgSendSuper()
/**
* Sends a message with a simple return value to the superclass of an instance of a class.
*
* @param super A pointer to an \c objc_super data structure. Pass values identifying the
* context the message was sent to, including the instance of the class that is to receive the
* message and the superclass at which to start searching for the method implementation. ★★
* @param op A pointer of type SEL. Pass the selector of the method that will handle the message.
* @param ...
* A variable argument list containing the arguments to the method.
*
* @return The return value of the method identified by \e op.
*
* @see objc_msgSend
*/
// super 里封装了消息接收者(方法调用者) 和 消息接收者的父类
id _Nullable objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
苹果注释说, superclass 的作用是从哪里开始查找方法实现; 即从 objc_super.super_class 开始查找,
所以, super 调用会直接从父类开始查找方法的实现
[super funcName];
而super调用的消息接收者仍然是子类对象, 只不过是从父类从开始查找方法的实现
相当于还是self在调用方法
objc_msgSendSuper2
★
而打断点分析汇编, 可以看到, 实际真正调用的是 objc_msgSendSuper2
// objc4/objc-abi.h
// objc_msgSendSuper2() takes the current search class, not its superclass.
id _Nullable objc_msgSendSuper2(struct objc_super * _Nonnull super, SEL _Nonnull op, ...);
struct objc_super2 {
id receiver; // 消息接收者
Class current_class; // 当前类, 即receiver的Class对象
};
汇编实现
该方法会拿到当前类, 在内部根据class找到superclass, 然后开始查找方法实现, 实际效果和 objc_msgSendSuper 是一样的
ENTRY _objc_msgSendSuper2
UNWIND _objc_msgSendSuper2, NoFrame
ldp p0, p16, [x0] // p0 = real receiver, p16 = class
ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
CacheLookup NORMAL, _objc_msgSendSuper2
END_ENTRY _objc_msgSendSuper2
class 和 superclass 方法
每个OC类都有class方法, 可想而知, class 的方法实现在 NSObject 上, 所以不管 self调用, 还是super调用, 最终都是在 NSObject 上找到
// objc4/NSObject.mm
+ (Class)class {
return self;
}
- (Class)class {
return object_getClass(self);
}
+ (Class)superclass {
return self->superclass;
}
// class_getSuperclass(object_getClass(self));
- (Class)superclass {
return [self class]->superclass;
}
网友评论