zoukankan      html  css  js  c++  java
  • class和object_getClass方法区别

    一、概述

    如上图:

    1.内存创建一个instance实例对象(Person *per),同时会创建一个与之对应的类对象(Class perClass)和元类对象(Class perMeta);

    注:实例对象通过calloc可创建多个,但类对象和元类对象在内存中只有一份,只创建一次;

    2.对象的本质,其实是C语言的结构体struct,各个对象的内存结构为:

    per:isa指针+仅存储Person类成员变量的值;

    Person:isa指针+superclass指针+存储成员变量的类型、名称,协议,对象方法等;

    perMeta:isa指针+superclass指针+仅存储类方法;

    3.isa指向:

    per:指向类对象Person;

    Person:指向元类对象perMeta;

    perMeta:指向基类(Root,如:NSObject)的元类对象meta(基类的元类对象的isa指向该元类对象自己);

    4.superclass指向:

    Person:指向父类>>基类的类对象指向nil;

    perMeta:指向父类>>基类的元类对象指向该基类的类对象;

    二、代码分析

    1)通过实例对象per获取类对象

    - (void)viewDidLoad {

        [super viewDidLoad];

        

        self.per1 = [[Person alloc] init];

        self.per2 = [[Person alloc] init];

        

        //类对象

        Class perClass1 = [self.per1 class];

        Class perGetClass2 = object_getClass(self.per1);

        Class person = [Person class];

        

        //打断点

        NSLog(@"---");

    }

    进入lldb模式:

    //所有的对象(包括类对象和实例对象)所属类的名字均为“Person”

    //查看类对象自身地址和self.per成员变量isa的地址值

    //p/x:以十六进制输出

    如上图说明三个问题:

    第一,每个实例对象开辟单独的内存;

    第二,同一种类对象仅在内存中开辟一次;

    第三,此处class方法和object_getClass无任何区别;

    2)通过类对象获取元类对象

    增加代码:

        //元类对象
        Class perMeta1 = [perGetClass2 class];
        Class perMeta2 = object_getClass(perGetClass2);

    lldb模式:

      报错:引用的成员变量isa不是结构体或共同体的成员;

    原因:结构体中的isa变量没有暴露出来,从而无法引用; 

     解决:自定义相同结构体,并将对象强制转换

    //添加代码

    struct lyb_objc_class {
        Class _Nonnull isa;
    };
    
    struct lyb_objc_class *perGetClass3 = (__bridge struct lyb_objc_class *)object_getClass(self.per1);

    //lldb模式:

    说明:

    1.perGetClass2和perGetClass3指的是同一个类对象;

    2.perMeta1的地址跟perGetClass2和perGetClass3的地址是相同的,说明此时class并没有返回元类对象,依然是类对象;

    3.perMeta2的地址和perGetClass3->isa指向的地址相同,说明object_getClass返回的是元类对象;

    4.元类对象的类名称和类对象的一样,依然是Person;

    3)通过元类对象获取基类的元类对象

    //添加代码

        struct lyb_objc_class *perMeta3 = (__bridge struct lyb_objc_class *)object_getClass(perGetClass2);

        //还是perMeta2

        Class rootMeta1 = [perMeta2 class];

        //基类(NSObject)的元类对象

        Class rootMeta2 = object_getClass(perMeta2);

    //lldb模式: 

    说明:

    1.class返回的依然是元类对象自身,object_getClass返回的是基类的元类对象;

    2.基类的元类对象的类名跟类对象的一样,为NSObject;

    三、结论

    当消息对象为实例对象instance时,class与object_getClass返回的对象地址一样;当消息对象为类对象,或元类对象时,class返回的消息对象本身,而object_getClass返回的是下一个对象;

    原因:因为class返回的是self,而object_getClass返回的是isa指向的对象;

    说明:以上源码查找在GitHub上有演示;

    补充:class <=> objc_getClass

    //代码

     

    //clang

     

    GitHub

  • 相关阅读:
    JS组件系列——表格组件神器:bootstrap table
    wcf寄宿到iis
    win10获取注册表权限
    在唯一密钥属性“fileExtension”设置为“.log”时,无法添加类型为“mimeMap”的重复集合项
    从TFS中的现有项目复制一份作为新项目,导致提交的服务器无法加载
    对程序集“”签名时加密失败 --“对程序集签名时出错
    session
    升级webapi依赖的Newtonsoft.json的版本(转)
    多线程相关
    Linq Group By 多个字段
  • 原文地址:https://www.cnblogs.com/lybSkill/p/10186663.html
Copyright © 2011-2022 走看看