iOS 大师养成之路--对象的本质

1、对象究竟是什么?

咱们的Xcode其实很强大,集成了不少牛逼的工具,clang就是其中之一,咱们可使用如下的命令对.m文件进行编译咱们就能够看到咱们的OC 编译到底层的C或者C++究竟是怎么样的c++

我这里的例子是使用的是main.m 文件,各位能够根据具体SDK的文件路径和须要编译的文件去编译研究
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk main.m  //模拟器的使用命令
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk  main.m //真机的使用命令
复制代码

咱们编译完看到的就是一个C++的结构体,没错就是一个objec_class的结构体,他的结构体长成这个样子: objective-c

固然下面还有不少的函数,太长了,不浪费地方了。咱们发现有些有意思的问题:

  • isa 为何没有? --> 在父类的结构体里面,直接继承
  • 它仍是继承之objc_object? -->

  • 个人对象呢为何只有一个isa 指针?--> 其实这里我只能这么解释下,可能不是很专业可是意思能表达清楚。在编译阶段,全部的类都有本身的内存空间了,至关于已经建好统一的毛坯了,只是要如何装修每一个对象有每一个对象的想法。这样一来对象实例化话时就很快了只要按照本身的想法直接装修好就行,再贴上本身的名字标示全部权。

2、神秘的isa

在上面我有说到对象在实例化时返回的就是一个isa,并且就干了一件事情,就是把咱们实例化出来的对象跟类进行绑定。那么isa就是是个啥玩意?且看如下分解:数组

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;//类对象
    uintptr_t bits;//位域
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};
复制代码
  • 咱们看到其实就是一个联合体,就多是bits 也多是cls.-->这也进一步说明对象的本质。
  • 那么要是bits还能怎么绑定类呢?咱们再看看bits都有啥
# define ISA_BITFIELD \
      uintptr_t nonpointer        : 1;                                       \表示是否对 isa 指针开启指针优化
      uintptr_t has_assoc         : 1;                                       \是否有关联对象
      uintptr_t has_cxx_dtor      : 1;                                       \否有 C++ 或者 Objc 的析构器
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \存储类指针的值
      uintptr_t magic             : 6;                                       \用于调试器判断当前对象是真的对象仍是没有初始化的空间
      uintptr_t weakly_referenced : 1;                                       \是否被指向或者曾经指向一个 ARC 的弱变量
      uintptr_t deallocating      : 1;                                       \是否正在释放
      uintptr_t has_sidetable_rc  : 1;                                       \当对象引用技术大于 10 时,则须要借用该变量存储进位
      uintptr_t extra_rc          : 19\当表示该对象的引用计数值,其实是引用计数值减 1,当大于10时须要借用上面的标志位
复制代码

这是一个宏定义的位域,后面的数字表示占有的位数。其实就是对isa进行了优化,把一个8字节的空间进行了高效使用,从而存储了更多的东西,如刚刚的cls 就存储在shiftcls中。缓存

isa走位

相信有不少人已经有所了解,可是说到isa,我仍是介绍下走位bash

  • 实例化对象的isa -> 类, 类的isa -> 元类,元类的isa -> 根元类,根元类的isa -> 根元类本身。流程大概就是如此,若是是NSObject的实例化对象会少一次。
  • 附上isa走位图
  • isa走位图解读,虚线表示的是isa走位,实线表示的是superclass的继承关系。rootClass是NSObject,万物皆对象

3、cache是什么?

字面意思就是缓存,事实上Runtime进行消息查找的时候若是每次查完就直接扔了很浪费,哪些常常用的或者最近查找过的方法会进行缓存,这样就提升了方法调用的效率。具体介绍能够参考我以前写过的关于cache_t的分析的文章 https://juejin.im/post/5e1469f6e51d4541657776b4app

4、bits 是什么?

不知道咱们是否是很好奇,既然对象实例化以后啥都没有那么我写的那些属性、方法都在哪呢?难道在类里面吗? 还真是,不过这个类是相对的,类是对象的类,元类是类的类,以此类推。bits里面就存了对象的属性、实例化方法(注意是实例化方法,类方法在元类的bits里面ide

一、bits 结构体

咱们看到了bits.data()返回的是一个class_rw_t *结构体指针,说明了这个bits里面存的就是这个结构体数据。函数

  • rw意味着什么,可读可写区域?谁写?确定不是咱们普通iOS开发人员写进去的,是编译器在编译、运行阶段对代码中的类、对象的解析翻译,把方法、属性、协议写入到这么一个可读可写的区域。
  • 所有都写在这里吗?不是。class_ro_t,read only还有一个只读区域
  • 那rw里写的是啥?类别、类拓展中的方法、属性、协议。
uint32_t flags;
    uint32_t version;

    const class_ro_t *ro;

    method_array_t methods;
    property_array_t properties;
    protocol_array_t protocols;

    Class firstSubclass;
    Class nextSiblingClass;

    char *demangledName;
复制代码
  • class_ro_t 结构体介绍,从下面的结构体咱们能够看到有方法数组、协议数组、属性数组,可是还有个ivars,咱们给类添加属性时,系统会默认实现set、get方法,同时还生成一个对应的成员变量。这个成员变量就存在ivars里。
struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    const uint8_t * ivarLayout;
    
    const char * name;
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;

    method_list_t *baseMethods() const {
        return baseMethodList;
    }
};
复制代码

二、实际看看验证下

咱们来先自定义一个类,配置好objc的源码,用LLDB调试看看内存中的数据工具

  • 准备好一个自定义的类,在main函数中直接调用

  • 获取bits中的数据 post

  • ro中的数据

  • 读属性,nickName 已经在数组中的第一个,总数也是一个(咱们的类中也只写了一个)。

  • 读方法,属性对应的set、get方法,咱们本身定义的一个实例化方以及一个c++的函数

  • 读成员变量,hobby以及属性自动生成的_nickName都在这里了

5、写在最后的感想

在这些底层的研究过程当中,思考苹果开发工程师的开发思路和设计思想是一件很享受的事情,弄清楚他们怎样作到让这个代码的效率如此之高对本身的开发水平提升有很好地帮助,用C++ 写过游戏的朋友估计体验比较深入,游戏全部的都是本身实现,除了场景以及渲染用到的游戏引擎。

有兴趣一块儿交流的朋友,能够加 QQ:578200388

相关文章
相关标签/搜索