iOS[super class]和[self class]

百家 作者:iOS开发 2018-08-15 11:37:18

点击上方“iOS开发”,选择“置顶公众号”

关键时刻,第一时间送达!


作者:大兵布莱恩特

链接:https://www.jianshu.com/p/3f2bcc588b44

iOS开发整理发布,转载请联系作者获得授权


最近小编所在公司招 iOS 开发职位,小编也出了几道面试题考察下候选人的 iOS 开发水平,其中有一道题如下:

@implementation Student : Person

- (instancetype)init
{
    self = [super init];
    if (self) {

        id obj1 = [self class];
        id obj2 = [super class];
        NSLog(@"%@",obj1);
        NSLog(@"%@",obj2);

    }
    return self;
}
@end

大部分候选人回答的 [self class ]输出 Student , [Super class]输出 Person, 只有少部分候选人回答都是输出 Student ,当然至于为什么输出结果都是 Student, 很少有能回答出来的.

接下来小编通过将Student.m 转换成 Cpp 文件,带大家一块去看看 [self class] 和 [super class] 背后究竟做了那些事情.

通过终端讲Student.m 转成Student.cpp 文件

2 找到 Student 的 init 方法 分析代码

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

  id obj1 = ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"));
  id obj2 = ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"));
  NSLog((NSString *)&__NSConstantStringImpl__var_folders_hj_pwgsq9614nb0vq4zd315tcx80000gn_T_Student_e7cbc1_mi_0,obj1);
  NSLog((NSString *)&__NSConstantStringImpl__var_folders_hj_pwgsq9614nb0vq4zd315tcx80000gn_T_Student_e7cbc1_mi_1,obj2);

 }
 return self;
}

由此可见 当我们调用[self class] 时候实际上编译器最终给我们转成
objc_msgSend(self,@selector(class)) , 消息的接收者是当前所在类的实例对象 , 这个时候就会去 self 所在类 Student 去查找 class 方法 ,
如果当前类 Student 没有 class 会向Student 父类 Person 类找 class 方法,
如果 Person 类也没有找到 class 方法,最终会找到最顶级父类 NSObject 的 class 方法,
最终找到 NSObject 的 class 方法 ,并调用了object_getClass(self) ,由于消息接收者是 self 当前类实例对象,
所以最终 [self class]输出 Student

那么为什么明明调用了 super 这个关键字 返回的[super class] 还是 Student 呢 ?

通过上边代码可知 , [super class] 最终编译器转化成了 objc_msgSendSuper(struct objc_super *,SEL) ,其中

/// Specifies the superclass of an instance. 
struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained _Nonnull id receiver;

    /// Specifies the particular superclass of the instance to message. 
#if !defined(__cplusplus)  &&  !__OBJC2__
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained _Nonnull Class class;
#else
    __unsafe_unretained _Nonnull Class super_class;
#endif
    /* super_class is the first class to search */
};
#endif

objc_super 是一个结构体,内部有一个 receiver 实例,和一 个 Class super_class,指向了当前类的父类 Class ,通过这个父类可以直接的从父类里边开始查找方法,由于消息接收者还是当前类的实例对象 self, 最终如果在父类中没有找到class 这个方法,会在 Person 类的父类 NSObject 中去查找 class 方法,由于 NSObject 的 class 方法,调用的是 object_getClass(self) ,所以最终消息接收者为 student 实例对象,所以返回的还是 Student .

当然我们知道了[ super class] 最终编译后代码样子,也可以自己手动去调用 objc_msgSendSuper 方法

- (instancetype)init
{
    self = [super init];
    if (self) {

        id obj1 = [self class];
        id obj2 = [super class];
        NSLog(@"%@",obj1);
        NSLog(@"%@",obj2);

        struct objc_super1 {
            __unsafe_unretained id receiver;
            Class superClass;
        };
        struct objc_super1 obj_super = {self,class_getSuperclass(object_getClass(self))};
        id obj3 = objc_msgSendSuper(&obj_super,@selector(class));

    }
    return self;
}

obj3输出的结果和直接调用 [super class]结果是一模一样的,刚才我们假设的情况都是 super Person 没有 class 方法,如果 Person 重写了 class 方法呢,将会怎么样?

当我们在 Student init 方法中调用 [super class] 时候 ,它首先会到 Person 类中查找 class 方法 ,当它发现了 Person 实现了 class 方法,就会调用[person class] 方法, object_getClass 这个时候 object_getClass(self), 这个 self 是 Student 的实例对象,就是消息接收者,所以即使重写了 Person 的 class 方法 ,依然返回的还是 Student ,除非来个极端的 把 class 方法 实现 返回个 nil , 这样最终调用[super class]结果才会返回nil

KVO巧妙的利用了子类 重写了 class 方法 ,让我们误以为 [person class] 还是当前类 Person ,而不是动态创建的子类 NSKVONotifily_Person 这个子类 , 就是让子类返回了父类的 Class ,所以调用 [person class] 返回的还是 Person 从而对开发者隐藏了 NSKVONotifily_Person子类的存在

- (Class)class {
    return class_getSuperclass(object_getClass(self));
}

【点击成为源码大神】

▼点击「阅读原文」进入程序员商城

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接
百度热搜榜
排名 热点 搜索指数