1. <tr id='mwxiw'><strong id='mwxiw'></strong><small id='mwxiw'></small><button id='mwxiw'></button><li id='mwxiw'><noscript id='mwxiw'><big id='mwxiw'></big><dt id='mwxiw'></dt></noscript></li></tr><ol id='mwxiw'><table id='mwxiw'><blockquote id='mwxiw'><tbody id='mwxiw'></tbody></blockquote></table></ol><u id='mwxiw'></u><kbd id='mwxiw'><kbd id='mwxiw'></kbd></kbd>
    1. <i id='mwxiw'></i>
      <span id='mwxiw'></span>

        <i id='mwxiw'><div id='mwxiw'><ins id='mwxiw'></ins></div></i>
      1. <dl id='mwxiw'></dl>

        <fieldset id='mwxiw'></fieldset>

        1. <acronym id='mwxiw'><em id='mwxiw'></em><td id='mwxiw'><div id='mwxiw'></div></td></acronym><address id='mwxiw'><big id='mwxiw'><big id='mwxiw'></big><legend id='mwxiw'></legend></big></address><ins id='mwxiw'></ins>

          <code id='mwxiw'><strong id='mwxiw'></strong></code>

          Objective-C Runtime:深入理解类与对象

          • 时间:
          • 浏览:8
          • 来源:124软件资讯网

            在那樱花盛开的季节

            概述

            常说Objective-C是一门动态语言  ,那么问题来了  ,这个动态体现在那些方面呢  ?

            实在最主要的体现就是Objective-C将许多静态语言在编译和链接时做的事情放到了运行时去做  ,它在运行时实现了对类、要领、成员变量、属性等信息的治理机制  。

            同时 ,运行时机制为我们开发历程提供许多便利之处 ,好比:

            • 在运行时建立或者修改一个类;

            • 在运行时修改成员变量、属性等;

            • 在运行时举行新闻分发和分发绑定;

            ......

            与之对应实现的就是Objective-C的Runtime机制  。

            Objective-C的Runtime现在有两个版本:Leagcy Runtime和Moden Runtime  。Leagcy Runtime是最早期给32位Mac OX Apps使用的 ,而Moden Runtime是给64位Mac OX Apps和iOS Apps使用的  。

            Runtime基本是C和汇编编写的  ,有一系列函数和数据结构组成的  ,具有公共接口的动态共享库  ,可见苹果为了动态系统的高效而作出的起劲 ,你可以在这里下载到苹果维护的开源代码  。

            同时  ,GNU也有一个开源的Runtime版本,他们在起劲保持一致 。其头文件都存放在/usr/include/objc目录下 。在Objective-C Runtime Reference中 ,有对Runtime函数使用细节的文档 。

            类与工具

            类的数据结构(Class)

            类的数据结构可以在objc/runtime.h源码中找到  ,如下所示:

            struct objc_class {
               //isa指针指向Class
                Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
            
            #if !__OBJC2__
                Class _Nullable super_class  OBJC2_UNAVAILABLE; // 父类
                const char * _Nonnull name OBJC2_UNAVAILABLE; // 类名
                long version  OBJC2_UNAVAILABLE; // 类的版本信息  ,默以为0
                long info  OBJC2_UNAVAILABLE; // 类信息  ,供运行时使用的一些位标识
                long instance_size  OBJC2_UNAVAILABLE; // 类的实例变量巨细
               // 类的成员变量列表
                struct objc_ivar_list * _Nullable ivars  OBJC2_UNAVAILABLE; 
                // 要领界说列表
                struct objc_method_list * _Nullable * _Nullable methodLists  OBJC2_UNAVAILABLE; 
                // 要领缓存
                struct objc_cache * _Nonnull cache  OBJC2_UNAVAILABLE; 
                // 协议列表
                struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE; 
            #endif
            
            } OBJC2_UNAVAILABLE;

            在Objective-C中类是由Class表现的  ,Class是一个指向struct objc_class的指针  。

            typedef struct objc_class *Class;

            在这个类的数据结构中 ,有几个字段需要诠释一下:

            • isa:在大多数的面向工具的语言中  ,都有类和工具的观点  。其中  ,工具是类的实例  ,是通过类数据结构的界说建立出来的  ,工具的isa指针是指向其所属类的  。同时  ,在Objective-C语言中  ,类自己也是一个工具  ,类作为工具时isa指针指向元类(Meta Class),后面会详解;

            • super_class:指向该类的父类  ,若是该类已经是根类(NSObject 或 NSProxy)  ,则 其super_class 为NULL;

            • version:该字段可以获取类的版本信息  ,在工具的序列化中可以通过类的版本信息来标识出差别版本的类界说中实例变量结构的改变  。

            objc_cache与cache

            上文object_class中结构体中的cache字段  ,是用来缓存使用过的要领  。这个字段是一个指向objc_cache的指针  ,详细数据结构如下所示:

            struct objc_cache {
                unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;
                unsigned int occupied                                    OBJC2_UNAVAILABLE;
                Method buckets[1]                                        OBJC2_UNAVAILABLE;
            };

            字段的详细形貌如下:

            • mask:整数类型  ,指定分配的缓存bucket的总数  。在要领查找历程中  ,Objective-C runtime使用这个字段来确定最先线性查找数组的索引位置  。指向要领selector的指针与该字段做一个AND位操作(index = (mask & selector))  。这可以看作为一个简朴的hash散列算法;

            • occupied:一个整数  ,指定现实占用的缓存bucket的总数;

            • buckets:指向Method数据结构指针的数组  。这个数组可能包罗不凌驾mask+1个元素  。需要注重的是  ,指针可能是NULL ,表现这个缓存bucket没有被占用  。另外被占用的bucket可能是不一连的  。这个数组可能会随着时间而增加  。

            关于上文object_class中结构体中的cache字段 ,对它的诠释如下:

            • cache:用于缓存最近使用的要领  ,一个工具可响应的要领列表中通常只有一部门是经常被挪用的  ,cache 则是用来缓存最常挪用的要领  ,从而制止每次要领挪用时都去查找工具的整个要领列表  ,提升性能  。

            • 在一些结构较为庞大的类关系中  ,一个工具的响应要领可能来自于继续的类结构中  ,此情形下查找响应的响应要领时就会比力耗时 ,通常使用cache缓存可以减低查找时间;

            举个栗子:

            NSDictionary *dic= [[NSDictionary alloc] init];//执行历程

            其缓存挪用要领的流程:

            1. [NSDictionary alloc]先被执行  。由于NSDictionary没有+alloc要领  ,于是去父类NSObject中去查找;

            2. 检测NSObject是否响应+alloc要领 ,发现响应  ,于是检测NSDictionary类  ,并凭据其所需的内存空间巨细最先分配内存空间  ,然后把isa指针指向NSDictionary类 。同时  ,+alloc要领也被加进对应类的cache列内外;

            3. 执行-init要领 ,若是NSDictionary响应该要领 ,则直接将该要领加入cache列表;若是不响应  ,则去父类查找;

            4. 在后期的操作中 ,若是再以[[NSDictionary alloc] init]这种方式来建立数组 ,则会直接从cache中取出响应的要领 ,直接挪用  。

            元类(Meta Class)

            上面讲到  ,有时间类也是一个工具  ,这种类工具是某一种类的实例  ,这种类就是元类(Meta Class) 。

            好比类与对应的实例形貌一样  ,元类则是类作为工具的形貌 。元类中要领列表对应的是类要领(Class Method)列表  ,这正是类作为一个工具所需要的  。

            当挪用该要领[NSArray alloc]时 ,Runtime就会在对应的元类要领列表查找其类对应的要领  ,并匹配挪用  。

            Meta Class是类工具的类  。

            官方的诠释如下所示: