小码哥iOS学习笔记第十四天: super

一、准备代码

  • Person继承自NSObject, 并实现-run方法

  • Student继承自Person, 并重写-run方法

  • main函数中, 执行下面的代码, 可以看到PersonStudent方法中的run都有打印结果

  • 那么super在底层是什么样的呢?

二、super

  • 使用终端, 执行下面的命令, 生成Student.cpp文件
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Student.m
复制代码
  • 可以在Student.cpp文件中找到-run方法的底层代码

  • 下面一句, 就是[super run];代码部分
((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("run"));
复制代码
  • 去掉类型转换
objc_msgSendSuper((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))},
                  sel_registerName("run"));
复制代码
  • 将第一个参数抽出
__rw_objc_super arg = {
    self,
    class_getSuperclass(objc_getClass("Student"))
};

objc_msgSendSuper(arg, sel_registerName("run"));
复制代码
  • 可以看到super的底层调用了objc_msgSendSuper方法, 并传入两个参数

    • __rw_objc_super: 结构体
    • sel_registerName("run"): 方法SEL
  • 查看源码中objc_super结构体

  • 去掉没有用的代码, 整理如下
struct objc_super {
    __unsafe_unretained _Nonnull id receiver;
    __unsafe_unretained _Nonnull Class super_class;
};
复制代码
  • 可以看到, 第一个成员变量是receiver, 第二个成员变量是super_class

  • 继续查看objc_msgSendSuper函数的定义

  • 在注释中可以看到对objc_super两个成员变量的解释

    • receiver: 消息接收者
    • super_class: 从super_class开始查找调用的方法
  • 从实际代码中可以看到, 这两个成员变量分别传入了self[Person class]

__rw_objc_super arg = {
        self,       // receiver
        class_getSuperclass(objc_getClass("Student"))       // super_class
    };
复制代码
  • 所以消息接收者是self, 从[Person class]中开始查找方法
  • objc_msgSendSuper的第二个参数是sel_registerName("run"), 即@selector(run)
  • 所以[super run];在底层代码的原意是: 给self发送一条消息, 消息名称是run, 这条消息从[Person class]开始查找

总结:
super的含义是, 查询方法的起点是父类, 不是本身的类对象
消息接收者是self, 不是父类对象
发送的消息是调用的方法

三、面试题

  • 下面的代码, 运行结果是什么, 为什么

  • 运行程序, 打印如下

2019-03-13 21:00:24.318811+0800 super[6493:1374771] Student
2019-03-13 21:00:24.319059+0800 super[6493:1374771] Person
2019-03-13 21:00:24.319077+0800 super[6493:1374771] ---------------------
2019-03-13 21:00:24.319093+0800 super[6493:1374771] Student
2019-03-13 21:00:24.319111+0800 super[6493:1374771] Person
复制代码
打印分析
  • 查看底层源码

  • 去掉类型转换, 底层代码如下
objc_msgSend(self, sel_registerName("class")
objc_msgSend(self, sel_registerName("superclass"))
objc_msgSendSuper((__rw_objc_super){self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"))
objc_msgSendSuper((__rw_objc_super){self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("superclass"))
复制代码
  • 前两个方法是给self发送消息, 消息名称是classsuperclass, 结果很明显就是查看自己的类型父类的类型
  • 后两个方法也是给self发送消息, 只不过是从父类开始查询classsuperclass方法, 而这两个方法都存在于NSObject
  • 消息接收者同样是self, 调用的方法也是相同, 所以结果就是自己的类型父类的类型

转载于:https://juejin.im/post/5c88eb0fe51d4512a370627a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值