<i id='dkvgx'></i>

          <fieldset id='dkvgx'></fieldset>

          <acronym id='dkvgx'><em id='dkvgx'></em><td id='dkvgx'><div id='dkvgx'></div></td></acronym><address id='dkvgx'><big id='dkvgx'><big id='dkvgx'></big><legend id='dkvgx'></legend></big></address>
          <dl id='dkvgx'></dl>

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

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

        2. <i id='dkvgx'><div id='dkvgx'><ins id='dkvgx'></ins></div></i>

          <ins id='dkvgx'></ins>

          深入理解Objective-C中类的数据结构

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

            一、类的结构

            OC 中的代码在底层实现  ,使用的是 C、C++ ,以是要研究 OC 中的类结构  ,可以将 OC 的代码转成 C++的代码即可  。首先看一下 NSObject 的结构是什么样子的  ,建立一个文件并简朴的编写如下代码:

            // CustomFile.m
            #import void test() {
             [NSObject alloc];
            }

            进入终端  ,输入指令:

            clang -rewrite-objc CustomFile.m

            默认天生一个 CustomFile.cpp 文件 。这个指令天生的代码会许多  ,也可以使用 xcrun 指令来指定一个特定的架构 ,这样的:

            xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc CustomFile.m -o CustomFile_arm64.cpp

            这样在 CustomFile_arm64.cpp 文件中会天生一个 真机下的运行代码  。相比之下 CustomFile_arm64.cpp 文件会比 CustomFile.cpp 小了许多  ,可是对于检察 NSObject 的现实结构都是可以的  。

            打开恣意一个 .cpp 文件 ,都可以找到这样的界说:

            struct NSObject_IMPL {
             Class isa;
            };

            其中 Class 的界说如下:

            typedef struct objc_class *Class;

            再来看一下在现实中的 NSObject 类的声明是什么样的:

            @interface NSObject  {
            #pragma clang diagnostic push
            #pragma clang diagnostic ignored "-Wobjc-interface-ivars"
             Class isa OBJC_ISA_AVAILABILITY;
            #pragma clang diagnostic pop
            }

            简化后是这样的:

            @interface NSObject {
             Class isa;
            }

            总之Class 是一个指针  ,NSObject_IMPL是一个结构体  ,与 NSObject 在结构上极为相似 。

            二、类继续后的结构

            建立一个 Person.m 文件  ,弄一个继续于 NSObject 的 Person 类  。代码编写如下:

            // Person.m
            #import  
            // 类的说明
            @interface Person : NSObject
            @end
             
            // 类的实现
            @implementation Person
            @end
             
            // 类的说明
            @interface Student : Person
            @end
             
            // 类的实现
            @implementation Student
            @end

            其中 Person 继续于 NSObject  ,Student 继续于 Person 于是在 .cpp 文件中找到这样的界说:

            struct Person_IMPL {
             struct NSObject_IMPL NSObject_IVARS;
            };
             
            struct Student_IMPL {
             struct Person_IMPL Person_IVARS;
            };

            NSObject_IVARS 看着这个命名就可以猜到是将父类的所有 ivar 都继续过来了  。

            似乎明确了一个套路

            在 NSObject 中只有一个 Class 类型的成员变量 isa ,在没有自界说任何的成员属性的情形下  ,继续的子类中的 ivar 都来自于父类 。

            若是说给 Person 与 Student 都界说一个成员变量  ,是这样的:

            struct Person_IMPL {
             struct NSObject_IMPL NSObject_IVARS;
             int _no;
            };
             
            struct Student_IMPL {
             struct Person_IMPL Person_IVARS;
             int _age;
            };

            终于对 Class 的一些套路有进一步的明白了 。

            三、添加要领后的结构

            建立一个 FunClass.m 文件 ,编写代码如下:

            // FunClass.m
            #import  
            // 类的说明
            @interface FunClass : NSObject
            - (void)testInstance;
            + (void)testClass;
            @end
             
            // 类的实现
            @implementation FunClass
            - (void)testInstance {
              
            }
             
            + (void)testClass {
              
            }
            @end

            最后发现在 .cpp 中类的结构没有任何的改变  ,是这样的:

            struct FunClass_IMPL {
             struct NSObject_IMPL NSObject_IVARS;
            };

            可是我们会发现另外一个问题  ,在 OC 中的要领酿成这样的了:

            // 实例要领
            _OBJC_$_INSTANCE_METHODS_FunClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
             sizeof(_objc_method),
             1,
             {{(struct objc_selector *)"testInstance", "v16@0:8", (void *)_I_FunClass_testInstance}}
            static void _I_FunClass_testInstance(FunClass * self, SEL _cmd) {
            }
             
            // 类要领
            _OBJC_$_CLASS_METHODS_FunClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
             sizeof(_objc_method),
             1,
             {{(struct objc_selector *)"testClass", "v16@0:8", (void *)_C_FunClass_testClass}}
            static void _C_FunClass_testClass(Class self, SEL _cmd) {
             
            }

            发现这几个特点:

            1. 实例要领有这个:_INSTANCE_METHODS_FunClass  ,类要领的是这个:_CLASS_METHODS_FunClass

            2. 两个要领都是 static 要领

            3. 要领都多了两个参数:self 与_cmd  ,这也回覆了为什么 self 与 _cmd 只能在要领中有的基础缘故原由  。

            关于 要领 的这部门先先容到这里 ,后期会有专门的专题  。