zoukankan      html  css  js  c++  java
  • 【OC底层】OC对象本质,如 isa, super-class

    Objective-C的本质

    1、我们编写的Objective-C,底层现实都是C/C++,代码生成步骤如下:
     

    2、在OC中的所有面向对象的实现,都是基于C/C++的数据结构实现的

    3、将Objective-C代码转换为CC++代码

      xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的CPP文件

        注:如果需要链接其他框架,使用-framework参数。比如-framework UIKit

    一个OC对象在内存中是如何布局的? 

    NSObject基类的实现:

    子类的实现:

    子类的拆解:

     1、在OC中的对象,就是 C++中的 struct来实现的

     2、每个OC对象中都会有一个 isa 的指针,isa指向的是 objc_class 结构体,如下(旧版OC原码):

    通过代码可以看得出在OC2 中已经不能通过  objc_method_list 之类的方式获取方法名、实例、协议之类的了,需要使用新的方法获取

    思路:自定义一个和oc源码中 objc_class 结构一样的结构体,然后将对象的isa 强转成我们自定义的那个,再去调用

    如下是OC中objc_class的源码(新版OC原码):

    新的OC版本中方法、属性、协议相关数据都存在了 bits 

    通过 bits.data() 返回 class_rw_t 结构,如下:

    bits.data() 的实现:

    其中需要 通过 & FAST_DATA_MASK 才能获取到真实的地址

    整体数据结构图:

     OC对象的分类

    Objective-C对象主要分为以下3类:

      1> instance对象(实例对象)

      2> class对象(对象)存储实例方法列表等信息

      3> meta-class对象(元类对象)存储类方法列表等信息

      注:一个类只会有一个类对象,一个元类对象,可以有多个实例对象

    通过下面的代码可以分别获取3种对象:

            NSObject* obj = [[NSObject alloc]init];
            const char* className = [@"NSObject" cStringUsingEncoding:NSUTF8StringEncoding];
            
            // 实例对象
            NSLog(@"instance: %p",obj);
            
            // 类对象
            NSLog(@"NSObject class: %p", [NSObject class]);
            // 同上
            NSLog(@"obj class: %p", [obj class]);
            // 如果传实例对象,获取到的还是类对象
            NSLog(@"get class: %p", object_getClass(obj));
            // 通过类名获取类对象
            NSLog(@"objcClass: %p", objc_getClass(className));
            
            // 元类对象
            // 必需要传入类对象才能获取元类对象
            NSLog(@"meta-class: %p", object_getClass([obj class]));
            // 通过类名获取元类对象
            NSLog(@"objcMetaClass: %p", objc_getMetaClass(className));
            
            // 判断是否是metaClass
            NSLog(@"isMetaClass1:%i",class_isMetaClass([NSObject class]));  // 0
            NSLog(@"isMetaClass2:%i",class_isMetaClass([[NSObject class] class])); // 0
            NSLog(@"isMetaClass3:%i",class_isMetaClass(object_getClass([NSObject class]))); // 1

    输出:

    2018-09-27 14:39:37.363 OC_isa_supclass[1350:102454] instance: 0x100202b50
    2018-09-27 14:39:37.364 OC_isa_supclass[1350:102454] NSObject class: 0x7fff760140f0
    2018-09-27 14:39:37.364 OC_isa_supclass[1350:102454] obj class: 0x7fff760140f0
    2018-09-27 14:39:37.364 OC_isa_supclass[1350:102454] get class: 0x7fff760140f0
    2018-09-27 14:39:37.365 OC_isa_supclass[1350:102454] objcClass: 0x7fff760140f0
    2018-09-27 14:39:37.365 OC_isa_supclass[1350:102454] meta-class: 0x7fff76014118
    2018-09-27 14:39:37.365 OC_isa_supclass[1350:102454] objcMetaClass: 0x7fff76014118
    2018-09-27 14:49:27.746 OC_isa_supclass[1360:106109] isMetaClass1:0
    2018-09-27 14:49:27.746 OC_isa_supclass[1360:106109] isMetaClass2:0
    2018-09-27 14:49:27.746 OC_isa_supclass[1360:106109] isMetaClass3:1

      1> 需要注意的是 object_getClass 方法,当传入的是实例对象,就会返回类对象,如果传入的是类对象就会返回元类对象

      2> 还有一点就是 [[NSObject class] class] 这样是获取不到元类对象的,这样获取到的还是类对象

        3> 另外里面还有两个 objc_ 开头的方法,分别是获取类对象和元类对象,但它是传入类名字符串就可以了,需要转换成 C语言的char

    1、instance对象

      instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象
      
      object1、object2是NSObject的instance对象(实例对象)

      它们是不同的两个对象,分别占据着两块不同的内存

     

      instance对象在内存中保存的信息包括:

      1> isa指针

      2> 其它成员变量

    2、class对象

     

     objectClass1 ~ objectClass5都是NSObject的class对象(类对象)

     NSObject类对象只有一个,所有实例对象的class属性获取到的都是同一个类对象 

       class对象在内存中存储的信息主要包括:

      1> isa指针

      2> superclass指针

      3> 类的属性信息(@property)、类的对象方法信息(instance method)

      4> 类的协议信息(protocol)、类的成员变量信息(ivar)

        ....

    3、meta-class对象

      

       objectMetaClass是NSObject的meta-class对象(元类对象)

       每个类在内存中有且只有一个meta-class对象

      meta-class对象在内存中存储的信息主要包括:

       1> isa指针

       2> superclass指针

       3> 类的类方法信息(class method)

        ... 

     注:class 对象和 meta-class 对象都是 Class 类型的,它们其实结构都是一样的,class对象中一样会包含 类方法,只不过那个类方法是 空的而已。

       同样,meta-class对象中也有 类的属性、对象方法、协议、成员变量,不过那些对应的值也都是空

    isa指针

    上面我们通过源码可以看到每个对象都有一个 isa 指针,isa指针作用是干嘛的呢?

    通过上图可以看出:

      1> instanceisa指向class
        当调用对象方法时,通过instanceisa找到class,最后找到对象方法的实现进行调用

      2> classisa指向meta-class

        当调用类方法时,通过classisa找到meta-class,最后找到类方法的实现进行调用

    class对象的superclass指针

    superclass是用于找父类的,比如子类调用某个方法,如果子类中没有,就会去父类找,底层就是通过superclass找到父类的,如下图:

     当Studentinstance对象要调用Person的对象方法时,会先通过isa找到Studentclass,然后通过superclass找到Person的class,最后找到对象方法的实现进行调用

      

     meta-class对象的superclass指针

     meta-class中的superclass基本和 class对象中的一样,不过有一点点区别,如图:

     

      当Student的class要调用Person的类方法时,会先通过isa找到Student的meta-class,然后通过superclass找到Person的meta-class,最后找到类方法的实现进行调用

      有什么区别呢?从这图可能看不出来,区别就是如果基类meta-class中都找不到类方法,那么它就会去从基类对象里面去找对象方法,OC的底层其实是不区分 对象方法与类方法的。

    isa、superclass总结 

     

    这张图能够清楚的描述 isa和superclass的作用和关系,下面是备注了一下,看得更加懂点。

     

    • instance的isa指向的是class对象
    • class的isa指向的是meta-class对象
    • 所有的meta-class的isa指向的都是基类的meta-class对象(重点)
    • class的superclass指向的是父类的class对象,如果没有父类,superclass指针为nil
    • meta-class的superclass指向的是父类的meta-class对象
    • 基类的meta-class的superclass指向的是基类的class对象(重点)

      instance调用对象方法的轨迹:

      实例对象会先通过isa找到class对象,判断里面有没有要调用的方法,如果有就直接调用,没有就会通过class对象中的superclass找到父类,然后在父类中判断是否有该方法,如果还没有就接着往上找。

       class调用类方法的轨迹:

       isa找meta-class,方法不存在,就通过superclass找父类,最后基类mate-class也没有的话还会去基类对象找,这样就会导致调用类方法可能会去调用实例对象的方法

     isa指针的一些问题

     上面已经说到了instance对象的isa指针指向的是class对象,那就是说instance对象的isa指针内存地址是不是就是class对象的内存地址呢?

     如果在以前的32位系统中确实如此,在64位系统中不是的,里面有一个点操作, ISA_MASK

      其中arm64和x86架构的这个 ISA_MASK的偏移地址是不一样的,如下图:

     

     class、meta-class对象的本质结构都是struct objc_class,如下图:

      

    -----------------------------

    本文参考借鉴MJ的教程视频,非常感谢.

  • 相关阅读:
    Python学习(二十四)—— 前端基础之Bookstrap
    Python学习(二十三)—— 前端基础之jQuery
    Python心得基础篇【4】文件操作
    Python心得基础篇【3】基本知识
    Python心得基础篇【2】函数
    WCF使用net.tcp绑定的配置实例
    WCF:如何将net.tcp协议寄宿到IIS
    WCF使用net.Tcp绑定时的注意事项
    解决WCF跨机器调用时发生“调用方未由服务进行身份验证”的错误
    在IIS中部署好WCF服务站点后,本机访问服务无问题,局域网中其他电脑访问不到
  • 原文地址:https://www.cnblogs.com/xgao/p/9708163.html
Copyright © 2011-2022 走看看