美文网首页
05-探索方法的归属和isa的走向

05-探索方法的归属和isa的走向

作者: luin4 | 来源:发表于2020-09-18 10:43 被阅读0次

[toc]

探索1: 方法的归属

通过上一节, 我们学习到了

  1. 通过lldb和内存地址, 从类以及元类里查找我们声明的(class_ro_t *)(成员变量列表), property_array_t(属性列表) ,method_array_t(方法列表), protocol_array_t(protocol_列表)
  2. isa和类继承关系走位
    那这一节我们主要来通过上节学到的知识点

1: 探索class_getInstanceMethod

我们先来看代码, 看完代码问题也就出现了, 他们分别会输出什么呢?
接下来请大家带着目的跟着我一起探索思考吧:


初始化类对象方式:
1: Class pClass = LLMethodClass.class;
or
2: Class pClass = object_getClass(person);
Class metaClass = objc_getMetaClass(className);
// - (void)sayHello;
// + (void)sayHappy;
Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));

Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));
Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));

  1. class_getInstanceMethod作用: 寻找实例方法
图1: class_getInstanceMethod方法实现-c749
  1. 我们在objc源码中查看它的源码:


    源码-c545
  2. 这里我们分别对lookUpImpOrForward_class_getMethod进行进一步探索, 发现大部分都看不懂, 但有一个方法让我看到了一丝丝熟悉的地方, 请看下图:

    图2: getMethodNoSuper_nolock方法实现-c749

图中标识的地方, 让我想到了 objc_class结构体, 以及我们上一节找到bits(平移32位内存)取到它里面存储的成员变量(ro), 属性(properties), 方法(methods)等等, 当然图只截了一小部分, 感兴趣的可以自己去看下:

图3: objc_class结构体回顾-c346
  1. 那么联想到这里, 我们就能大概猜到, 当我们调用class_getInstanceMethod方法时, 它在源码里会根据传入的cls, 来查找它的结构体里有没有我们要获取的方法.
  2. 那我们在回过头来看class_getInstanceMethod(pClass, @selector(sayHello));这段代码, 就是要让我们根据cls类的bits里, 来查找是否有sel这个实例方法, 验证(平移cls内存地址获取bits, 打印methods)后, 发现是有这个方法的.
  3. Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));步骤5相同的验证方法, 发现元类里是没有sayHello方法的, 但是我们找到了sayHappy的方法, 说到这里要拓展一个知识点在源码的世界里, 只有实例方法, 是没有类方法这个说法的(OC层面才会有这些说法), 因为每个类每个元类, 他们都是对象, 他们的方法都存储在他们的父级里.
  4. 接下来继续从他的超类里查找, 也是没有的.
  5. 接下来, 我们也就知道method4和method5的结果, 在类里找类方法肯定没有, 在元类里找类方法, 那一找一个准.
  6. 最后我们来输出验证下:


    最终输出结果-c749

2: 探索class_getClassMethod


初始化类对象方式:
1: Class pClass = LLMethodClass.class;
or
2: Class pClass = object_getClass(person);
Class metaClass = objc_getMetaClass(className);
// - (void)sayHello;
// + (void)sayHappy;
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));

Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));

  1. 苹果官方文档说明


    -c563
  1. 顾名思义, 该方法肯定是从cls里查找是否有sel类方法,查找它的源码
    class_getClassMethod方法实现-c563

这是说, 会从我们传进来的类的元类中查找元类的实例方法, 变相的也佐证了我们上面说过的一句话:在底层, 没有类方法, 都是实例方法.

  1. 这里有个坑点->cls->getMeta(), 我们来看它的实现:
    -c563

这里是说当前cls是元类时, 直接返回自身, 否则会调用它的isa获取它的元类.
这里是因为isa元类走向, 最终会指向根元类并一直循环指向根元类, 这么写就是为了防止死循环.

  1. 看到这里, 一步一步来分析, 很容易就得出结果:

method1: 类 -> 元类 -> 元类(isMetaClass返回自身)中没有sayHello实例方法.
method2: 元类-> 元类(isMetaClass返回自身)中没有sayHello实例方法.
method3: 类 -> 元类 -> 元类(isMetaClass返回自身)中有sayHappy类方法
method4: 元类 -> 元类(isMetaClass返回自身)中有sayHappy类方法

  1. 打印验证


    -c677

3: 探索class_getMethodImplementation

初始化类对象方式:
1: Class pClass = LLMethodClass.class;
or
2: Class pClass = object_getClass(person);
Class metaClass = objc_getMetaClass(className);
// - (void)sayHello;
// + (void)sayHappy;
Method method1 = class_getMethodImplementation(pClass, @selector(sayHello));
Method method2 = class_getMethodImplementation(metaClass, @selector(sayHello));

Method method3 = class_getMethodImplementation(pClass, @selector(sayHappy));
Method method4 = class_getMethodImplementation(metaClass, @selector(sayHappy));
class_getMethodImplementation实现-c749
***********************************************************************
* lookUpImpOrForward.
* //标准的IMP查找。
* The standard IMP lookup. 
* //没有LOOKUP_INITIALIZE:试图避免+initialize(但有时失败)
* Without LOOKUP_INITIALIZE: tries to avoid +initialize (but sometimes fails)
* //没有LOOKUP_CACHE:跳过乐观解锁查找(但在其他地方使用缓存)
* Without LOOKUP_CACHE: skips optimistic unlocked lookup (but uses cache elsewhere)
* //大多数调用者应该使用LOOKUP_INITIALIZE和LOOKUP_CACHE
* Most callers should use LOOKUP_INITIALIZE and LOOKUP_CACHE
****** //inst是cls的实例或子类,如果不知道,则为nil。
****** inst is an instance of cls or a subclass thereof, or nil if none is known. 
* //如果cls是一个未初始化的元类,那么一个非nil inst会更快
* If cls is an un-initialized metaclass then a non-nil inst is faster.
* //可能返回_objc_msgForward_impcache。外用IMPs
* May return _objc_msgForward_impcache. IMPs destined for external use 
* //必须转换为_objc_msgForward或_objc_msgForward_stret。
* must be converted to _objc_msgForward or _objc_msgForward_stret.
* //如果你根本不想转发,使用LOOKUP_NIL
* If you don't want forwarding at all, use LOOKUP_NIL.
**********************************************************************/
lookUpImpOrForward实现-c749
  1. class_getMethodImplementation实际是从cls中的cache_t缓存中查找sel的实现, 查找到返回imp的地址, 没有查找到就会返回一个msg_forward_name的地址(objc中没有,在llvm中查找到了msg_forward_name, 后续看不懂, 有时间再看)

  2. 看到这里, 一步一步来分析, 很容易就得出结果:

    method1: 类中有sayHello实例方法, 所以也查找到它的imp
    method2: 元类中没有sayHello实例方法, 返回msg_forward_name地址
    method3: 类中没有sayHappy类方法, 返回msg_forward_name地址
    method4: 元类有sayHappy类方法, 所以也查找到它的imp

  3. 打印验证

    class_getMethodImplementation验证-c747
    imp2imp3的地址是一样的, 都是消息转发后的imp实现, 具体实现的是, 暂不得而知.

2: 探索isKindOfClassisMemberOfClass

1: isKindOfClass探索

isKindOfClass图示1-c600 isKindOfClass图示2-c600
  • 图示1两个方法都是伪实现,断点并不走这里, 全局搜索下, 只有这个实现, 断点在这里验证

  • 图示2是最终走向(类方法和实例方法), 断点会停到这里, 当环境为 OBJC2时进入断点处, 正常环境则会进入msg_send图示1.

  • 为什么会走到里: 因为编译时就确定的原因, 所以去llvm中查找, 发现和alloc的消息转发定义在了一起, so 骚操作, 你懂得...

  • 作用: 通过查找obj的元类, 并递归循环元类的superclass与otherClass进行对比

    该方法中, 需要注意isa也就是元类的继承关系, 是的元类也存在继承关系:
    元类 -> 根元类(metaClass) -> 根类(NSObject) -> nil

isa走向-c600

2: isKindOfClass探索

isMemberOfClass图示-c382
  • 作用:
    • +isMemberOfClass: 通过与查找自身的元类, 并与自身进行对比
    • -isMemberOfClass: 通过与查找自身的类型, 并与自身进行对比

相关文章

  • 05-探索方法的归属和isa的走向

    [toc] 探索1: 方法的归属 通过上一节, 我们学习到了通过lldb和内存地址, 从类以及元类里查找我们声明的...

  • iOS底层探索004-类分析

    iOS底层探索-目录 1. 类的分析 主要分析两个部分:isa的走向和继承关系 isa分析 类的isa走向,参考这...

  • 类的结构分析

    isa继续探索 在对象探索-初探isa文章中,简单探索了isa的构成,这篇文章主要将isa之间的关系及类的内存结构...

  • isa探索

    打开objc-750源码,找到结构体objc_object,直接对isa源码分析。 从代码中我们知道isa的类型是...

  • 经典面试题分析(一)

    几道isa相关的经典面试题以及分析 前期准备: 方法归属相关测试 第一道 输出结果: class_getInsta...

  • ios isa的探索

    1. isa在alloc中的实现 在alloc探索[https://www.jianshu.com/p/08079...

  • iOS - isa 和 类的关系探索

    我们使用的所有对象的都是继承至NSObject, 你是否会探索下NSObject到底是啥?点进去可以看到出了方法之...

  • OC基础- isa(3)

    isa指针 instance的isa指向class当调用对象方法的时候,通过isa找到class,最后找到象方法的...

  • iOS原理探索05 -- 类方法&经典面试题分析

    类方法的归属问题 我们在iOS原理探索04--类结构的分析中知道 类的实例方法和类的属性都存在bits中,我们发现...

  • iOS底层原理--isa&类结构探究(文末技术合集参考)

    开始探究 本篇开始正式研究类和isa,归根结底还是围绕类展开探索。研究类其实无非就是研究isa的走位和类的继承关系...

网友评论

      本文标题:05-探索方法的归属和isa的走向

      本文链接:https://www.haomeiwen.com/subject/btndyktx.html