一、概述

如上图:

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

class和object_getClass方法区别的更多相关文章

  1. querySelectorAll 方法相比 getElementsBy 系列方法区别

    最近有人问到querySelectorAll 方法相比 getElementsBy 系列方法区别,一时没想起来说些什么,今天查下文档,总结一下它们的区别,以便自己理解. 1. W3C 标准queryS ...

  2. 浅析对象访问属性的"."和"[]"方法区别

    在JavaScript中通常使用”."运算符来存取对象的属性的值.或者使用[]作为一个关联数组来存取对象的属性.但是这两种方式有什么区别了? 例如,读取object中的property属性值 ...

  3. JAVAAPI学习之Calendar类;Calendar类set()、add()、roll()方法区别

    JAVAAPI学习之Calendar类 http://blog.csdn.net/myjlvzlp/article/details/8065775(写的很好,清晰易懂) Calendar类set(). ...

  4. java中File类中list()和listFiles()方法区别

    list()和listFiles()方法区别: 1.返回值类型不同:前者为String数组,后者为File对象数组 2.数组中元素内容不同:前者为string类型的[文件名](包含后缀名),后者为Fi ...

  5. jQuery方法区别:click() bind() live() delegate()区别

    今天看到一篇jquery 事件的文章,自己写了个小例子,虽然2种方式都可以实现,但是不太明白,找了点资料 $("#box1").delegate("p",&qu ...

  6. JavaScript toString、String和stringify方法区别

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  7. Java构造器(构造方法)与方法区别

    构造器,又称为构造方法.构造器用于构造该类的实例,也就是对象. 格式如下:[修饰符]  类名 (形参列表){//n条语句} 构造方法是一种特殊的方法,与一般的方法区别:  1.构造方法的名字必须与定义 ...

  8. DevOps - 与敏捷方法区别

    章节 DevOps – 为什么 DevOps – 与传统方式区别 DevOps – 优势 DevOps – 不适用 DevOps – 生命周期 DevOps – 与敏捷方法区别 DevOps – 实施 ...

  9. 从源码看commit和commitAllowingStateLoss方法区别

    Fragment介绍 在很久以前,也就是我刚开始写Android时(大约在2012年的冬天--),那时候如果要实现像下面微信一样的Tab切换页面,需要继承TabActivity,然后使用TabHost ...

随机推荐

  1. Android上实现视频录制

    首先,我们肯定要用到摄像头,因此需要在Manifest文件中声明使用权限: <uses-permission android:name="android.permission.CAME ...

  2. xxxx签名算法逆向&&python脚本实现

    前言 有一段时间没看安卓了,找几个软件练练手. 这是一个考驾照用的 app. 官方网址: http://www.******baodian.com/ 本文就分析一下在 重置密码时对 数据包 进行签名来 ...

  3. redis 概述、windows版本下载启动访问退出安装、中文乱码、RedisDesktopManager下载

    redis 概述 redis的key是string类型的:value有多种类型,但放入的不是特定类型数据,添加的都是string,只是redis把这些值组织成了各种数据结构.key和相应的值都是str ...

  4. Django 简单用户注册

    项目名 macboy app名 t1 1.项目macboy urls.py from django.conf.urls import url, include urlpatterns = [ url( ...

  5. 二、ionic如何使用外链

    1.ionic如何使用外链并返回原有页面? html如下: 对应的controller如下: (function() { angular.module('app').controller('extra ...

  6. CSS 小结笔记之定位

    定位也是Css中一个非常强大的属性.定位主要是用来移动盒子,将其移动到我们想要的位置. 定位分为两部分 1.边偏移 left | right |top |bottom:偏移大小:(边偏移一般制定上就不 ...

  7. CSS 实例之文字的凸起与凹陷

    一些页面会有一些凹凸文字效果,这个主要是设置背景+文字阴影来达成这个效果的.文字阴影使用方法如下: text-shadow: 水平位置 垂直位置 模糊距离 阴影颜色 具体代码如下: body { ba ...

  8. Java 两个日期间的天数计算

    在Java中计算两个日期间的天数,大致有2种方法:一是使用原生JDK进行计算,在JDK8中提供了更为直接和完善的方法:二是使用第三方库. 1.使用原生的JDK private static long  ...

  9. 在asp.net一般应用程序中使用session

    通常我们经常,通过session判定用户是否登录.还有一些临时的.重要的数据也尝尝存放在Session中. 在页面我们很容易的得到Session的值,但在类中就会遇到一些问题.也知道通过下面的方法得到 ...

  10. 关于php优化 你必须知道的一些事情

    1. 用单引号代替双引号来包含字符串,这样做会更快一些.因为 PHP 会在双引号包围的 字符串中搜寻变量,单引号则不会,注意:只有 echo 能这么做,它是一种可以把多个字符 串当作参数的“函数”(译 ...