Objective-C中的 self 与 super 的理解

187 阅读3分钟

准备:

Person类、和Student类,其中 Person继承自NSObject, Student继承自Person

@interface Person : NSObject
@end
@implementation Person
@end

============

@interface Student : Person
@end

@implementation Student

- (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

main.m方法中创建一个Student的实例。

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Student *stu = [[Student alloc] init];
    }
    return 0;
}

打印结果:
2020-08-26 20:11:35.923899+0800 LearningRuntime[11990:229658] [self class] = Student
2020-08-26 20:11:35.925986+0800 LearningRuntime[11990:229658] [super class] = Student
2020-08-26 20:11:35.926719+0800 LearningRuntime[11990:229658] [self superclass] = Person
2020-08-26 20:11:35.927085+0800 LearningRuntime[11990:229658] [super superclass] = Person

如果结果正如你所料,就无需往下看了。(不错~)

分析

为什么打印的结果和我们预料的不一样呢?为了探个究竟,我们可以将OC代码转为C++,弄清楚这几句打印底层是如何实现的。

终端进入项目所在目录,执行以下命令,将OC转为C++代码.

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Student.m 

转化后结果:

static instancetype _I_Student_init(Student * self, SEL _cmd) {
    if (self = ((Student *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("init"))) {

        ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"));
        ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"));
        ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("superclass"));
        ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("superclass"));
    }
    return self;
}

简化后核心代码如下:

static instancetype _I_Student_init(Student * self, SEL _cmd) {
    if (self = objc_msgSendSuper({self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("init"))) {
    	// [self class]
        objc_msgSend(self, sel_registerName("class");  
        // [super class]
        objc_msgSendSuper({self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"));
        // [self superclass]
        objc_msgSend(self, sel_registerName("superclass")); 
        // [super superclass]
        objc_msgSendSuper({self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("superclass")); 
    }
    return self;
}

objc_msgSendSuper 的第一个参数是一个__rw_objc_super结构体实例,__rw_objc_super 的定义如下:

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) {} 
};

由上可知:

  1. [self class] 分析:

[self class] 底层实际上转成了 objc_msgSend(self, sel_registerName("class"),利用消息机制给self发送了一条消息名为class的消息。消息机制会根据selfisa指针去其类对象(Student类对象)的方法列表找,找不到就会根据superclass指针往上找,最终会在NSObject类对象中找到并调用,我们看下NSObject中的方法实现。

	// 类方法
  + (Class)class {
  		return self;
      }
   // 实例方法
   - (Class)class {
       return object_getClass(self);  // 获取类对象
   }

可以看到,NSObject对象方法class 实际上是调用了object_getClass(self); 最终返回实例的类对象(即 Student类对象)

  1. [super class] 分析:

    [super class] 底层实际上转成了 objc_msgSendSuper({self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class")), 要理解这句话,需要看下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
    */
    

OBJC_EXPORT id _Nullable objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);

由方法定义可知: `objc_msgSendSuper`方法第一个参数为`objc_super` (`objc_super`中包含了`消息的接收者``开始搜索方法的类`),第二个参数为`消息名称`。 因此,`[super class]` 的消息接收者实际上还是`self`,只不过是从`superclass`(即`Person类对象`)开始搜索方法。我们知道`class`的实现是在`NSObject`中,所以最终也会调用`object_getClass(self)`方法获取类对象,此时的`self`就是消息的接收者(即`Student`). 所以最终获得类对象就是`Student类对象`3. `[self superclass]``[super superclass]` 分析:   
理解了`self``super`的调用方法的区别,那这里只要知道了`superclass`方法底层是如何实现就没什么问题了. 在runtime源码中找到`NSObject.mm`文件,可以看到`superclass`方法的实现如下:
```cpp
// 类方法
 + (Class)superclass {
  	 return self->superclass;
 }
 // 实例方法
 - (Class)superclass {
     return [self class]->superclass;  // 获取当前类对象的父类
 }

本例会调用实例方法,所以最终返回的是Student类对象的父类,即Person类对象

参考

  1. runtime源码
  2. MJ 底层教程