根据上一篇博客iOS-class、object_getClass、objc_getClass、objc_getMetaClass区别的研究发现,发现主要还是class方法和objc_getClass方法的区别,因此本篇文章主要讲述一下class方法和objc_getClass方法。

一、Object(objc实例对象),Class(类),Metaclass(元类),Rootclass(根类),Rootclass‘s metaclass(根元类)

首先说下Objective-C中类的几种数据结构;在Objective-C的类型结构中,Object(实例),Class(类),Metaclass(元类),Rootclass(根类),Rootclass‘s metaclass(根元类),且这些都是对象。

我们可用过两张图了解一下上述类型中的关系图

1、经典的Objective-C的对象模型图

2、 实例对象(Object),类(CLass),元类(Metaclass)之间的关系

实例对象(Object): 我们创建的一个对象或实例objc其实就是一个struct objc_object结构体,这个结构体只有一个成员变量,这是一个Class类型的变量isa,也是一个结构体指针,这个objc对象的isa指针指向他的类对象(即平时我们所说的类)

类(CLass):存储Object实例的相关数据,如:实例方法列表、成员变量列表、属性列表。

元类(Metaclass):存储Class相关的数据,如:类方法列表、类的信息等。

参考苹果官方公开源码

objc4源码在线浏览

objc4源码下载

二、class方法和objc_getClass方法

1、class方法

实例方法 - (CLass)class;

类方法 + (Classs)class

在苹果公开的官方objc源码,NSObject.mm文件中:

// 类方法,返回自身
+ (Class)class {return self;
}// 实例方法,查找isa(类)
- (Class)class {return object_getClass(self);
}

2、object_getClass方法

object_getClass(id _Nullable obj) 

(1)传入参数:obj可能是instance对象、class对象、meta-class对象

(2)返回值:

【1】如果是instance对象,返回class对象

【2】如果是class对象,返回meta-class对象

【3】如果是meta-class对象,返回NSObject(基类)的meta-class对象

官方源码:

/***********************************************************************
* object_getClass.
* Locking: None. If you add locking, tell gdb (rdar://7516456).
**********************************************************************/
Class object_getClass(id obj)
{if (obj) return obj->getIsa();else return Nil;
}

三、objc对象类型

我们首先通过objc_getClass方法获取isa指针,即指向类对象的指针

objc_getMetaClass方法获取类对象中的isa指针,即指向元类对象的指针

代码如下:

Class c1 = objc_getClass("People");
Class c2 = objc_getMetaClass("People");NSLog(@"objc_getClass----              %p",c1);
NSLog(@"objc_getMetaClass----          %p",c2);

输出结果:

1、obj为实例对象

在Object-C中,Object本质上是一个struct,在这个struct中会保存一个名为isa的指针,该指针会指向该Object的类。定义如下所示:

/// Represents an instance of a class.
struct objc_object {Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;

我们初始化一个类的实例可以直接用id来定义,那么id就是上面这样定义的,所以类的实例初始化完了之后,它的内部就多了一个isa指针,这个指针类型指向的是struct objc_class的结构体,其实也就是指向了这个实例所属的类。

代码如下:

    //obj为实例对象id obj = [[People alloc]init];People *people = obj;/*----obj为实例对象----*/Class cls = [obj class];Class cls2 = object_getClass(obj);Class cls3 = [people class];Class cls4 = object_getClass(people);NSLog(@"");NSLog(@"----obj为实例对象----");NSLog(@"实例对象:class----              %p" , cls);NSLog(@"实例对象:object_getClass----    %p" , cls2);NSLog(@"实例对象:class----              %p" , cls3);NSLog(@"实例对象:object_getClass----    %p" , cls4);

输出结果:

当obj为实例变量时

object_getClass(obj)与[obj class]输出结果一直,均获得isa指针,即指向类对象的指针。

2、obj为Class类对象

在Objective-C中,任何类的定义都是对象(除了int、char等这些基本类型)。类和类的实例(对象)没有任何本质上的区别。任何对象都有isa指针。

我们打开Xcode中 <obc/runtime.h> 头文件或者苹果公开的objc官方源码runtime.h文件中,里面有一个结构体定义

struct object_class{Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__Class super_class                        OBJC2_UNAVAILABLE;  // 父类const char *name                         OBJC2_UNAVAILABLE;  // 类名long version                             OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0long info                                OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识long instance_size                       OBJC2_UNAVAILABLE;  // 该类的实例变量大小struct objc_ivar_list *ivars             OBJC2_UNAVAILABLE;  // 该类的成员变量链表struct objc_method_list *methodLists     OBJC2_UNAVAILABLE;  // 方法定义的链表struct objc_cache *cache                 OBJC2_UNAVAILABLE;  // 方法缓存struct objc_protocol_list *protocols     OBJC2_UNAVAILABLE;  // 协议链表
#endif
}OBJC2_UNAVAILABLE;

这个结构体其实就是我们所说的   ,他的 Class isa这个指针的类型点进去会发现,定义如下:

// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

原来isa指针指向的依然是个 objc_class 结构体,只不过为了语义化起个名字叫Class

代码如下:

    //obj为实例对象id obj = [[People alloc]init];People *people = obj;//classObj为类对象Class classObj = [obj class];/*----obj为类对象----*/Class clsc = [classObj class];Class clsc2 = object_getClass(classObj);NSLog(@"");NSLog(@"----obj为类对象----");NSLog(@"类对象:class----               %p" , clsc);NSLog(@"类对象:object_getClass----     %p" , clsc2);

输出结果:

当obj为类对象时

object_getClass(obj)返回类对象中的isa指针,即指向元类对象的指针;

[obj class]返回的则是类对象其本身

3、obj为Metaclass类(元类)对象

Metaclass元类与Class的结构是一样的,只是职能不同。

类(CLass):存储Object实例的相关数据,如:实例方法列表、成员变量列表、属性列表。

元类(Metaclass):存储Class相关的数据,如:类方法列表、类的信息等。我们可以参考头部实例对象(Object),类(CLass),元类(Metaclass)之间的关系图解

代码如下:

    //obj为实例对象id obj = [[People alloc]init];//classObj为类对象Class classObj = [obj class];//metaClassObj为元类对象Class metaClassObj = object_getClass(classObj);/*----obj为元类对象----*/Class clso = [metaClassObj class];Class clso2 = object_getClass(metaClassObj);NSLog(@"");NSLog(@"----obj为元类对象----");NSLog(@"元类对象:class----              %p" , clso);NSLog(@"元类对象:object_getClass----    %p" , clso2);

输出结果:

当obj为Metaclass(元类)对象时

object_getClass(obj)返回元类对象中的isa指针,因为元类对象的isa指针指向根类,所有返回的是根类对象的地址指针;

[obj class]返回的则是元类本身

4、obj为Rootclass类(根类)对象

Rootclass就是根类,任何类的Metaclass中的isa指针都是指向根类。且结构与Class结构是一样的。

代码如下:

    //obj为实例对象id obj = [[People alloc]init];//classObj为类对象Class classObj = [obj class];//metaClassObj为元类对象Class metaClassObj = object_getClass(classObj);//rootClassObj为根类对象Class rootClassObj = object_getClass(metaClassObj);/*----obj为根类对象----*/Class clsr = [rootClassObj class];Class clsr2 = object_getClass(rootClassObj);NSLog(@"");NSLog(@"----obj为根类对象----");NSLog(@"根类对象:class----              %p" , clsr);NSLog(@"根类对象:object_getClass----    %p" , clsr2);

输出结果:

当obj为Rootclass(根类)对象时

object_getClass(obj)返回根类对象中的isa指针,因为根类对象的isa指针指向Rootclass‘s metaclass(根元类),即返回的是根元类的地址指针;

[obj class]返回的则是其本身。
因为根类的isa指针其实是指向本身的,所有根元类其实就是根类,所有输出的结果是一样的。

四、结论

1、object_getClass(obj)

返回的是obj的isa指针

2、[obj class]

(1)obj为实例对象
调用的是实例方法:- (Class)class,返回的obj对象中的isa指针;

(2)obj为类对象(包括元类和根类以及根元类)
调用的是类方法:+ (Class)class,返回的结果为调用者本身。

这时候我们再回过头看看Object-C的对象模型图,思考一下会发现

1、内存创建一个instance实例对象(People *people),同时会创建一个与之对应的类对象(Class peopleClass)和元类对象(Class peopleMeta);

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

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

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

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

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

3、isa指向:

people:指向类对象People;

People:指向元类对象peopleMeta;

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

4、superclass指向:

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

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

GitHub示例代码Demo

参考文章:

iOS笔记--class方法和objc_getClass方法

object_getClass(obj)与[obj class]的区别

class和object_getClass方法区别

iOS-class方法和objc_getClass方法相关推荐

  1. iOS load方法和initialize方法的异同

    对于OC中的类来说,在runtime中会有两个方法被调用: +load +initialize 这两个方法看起来都是在类初始的时候调用的,但其实还是有一些异同,从而可以用来做一些行为. +load 首 ...

  2. IOS开发基础Object-C( 04)—构造方法和description方法

    在上一篇博客中,我们简单介绍了一下点语法和self,相信大家对点语法以及self有了一点的了解,点语法的本质就是调用get方法和set方法.那么今天我们再来介绍一下构造方法和description. ...

  3. JS中的call()方法和apply()方法用法总结

    1. 每个函数都包含两个非继承而来的方法:call()方法和apply()方法. 2. 相同点:这两个方法的作用是一样的. 都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖 ...

  4. python 推迟运行_一文看懂Python的time模块sleep()方法和strftime()方法

    概述 今天主要介绍一下Python的time sleep()方法和strftime()方法. 一.Python time sleep()方法 Python time sleep() 函数推迟调用线程的 ...

  5. JS服务器端开发基础篇(Array.slice方法和splice方法)

    Array.slice方法和splice方法在众多的JS数组中属于比较复杂的一个方法,而且容易记混.搜索网络上很多资料都没有发现系统的总结.特别归纳如下,不完全处还希望各位批评指正.  一.slice ...

  6. Loader的load方法和loadBytes方法LoaderContext参数

    (1)在看代码的时候还发现一个以前没有这么注意的问题,也mark一下. 关于Loader的load方法和loadBytes方法LoaderContext参数的问题.. 要加载某个SWF到自己的安全域内 ...

  7. ThinkPHP 中M方法和D方法的具体区别

    M方法和D方法的区别 ThinkPHP 中M方法和D方法都用于实例化一个模型类,M方法 用于高效实例化一个基础模型类,而 D方法 用于实例化一个用户定义模型类. 使用M方法 如果是如下情况,请考虑使用 ...

  8. asp.net TemplateField模板中的Bind方法和Eval方法

    TemplateField模板中为了能够有限制的或者取出数据库中某列的值时,可以用Bind和Eval方法来实现.以下是Bind方法的格式,Eval的格式也是和Bind一样的. Bind("列 ...

  9. hashcode()方法和equals()方法

    一.hashcode()方法和equals()方法的介绍 Java的基类Object提供了一些方法,其中equals()方法用于判断两个对象是否相等,hashCode()方法用于计算对象的哈希码.eq ...

最新文章

  1. 计算机统考408卷子谁批,【计算机统考】你对计算机统考408了解有多少?
  2. unity android模糊ios清晰,Unity NGUI UI 在iOS端的锯齿、模糊、颗粒感问题
  3. [NET] 如何从 Winform 移植到 Webform [自己搞定HTTP协议]
  4. 深入学习Redis高可用架构:哨兵原理及实践
  5. jquery.mobile手机网页简要
  6. 启动Tomcat一闪而过解决
  7. BZOJ 2742: [HEOI2012]Akai的数学作业
  8. Thymeleaf视图
  9. 六石编程学:数据正确是软件的基石
  10. ollvm源码分析之控制流扁平化(3)
  11. 【支持向量机SVM系列教程3】支持向量回归SVR
  12. 大型仿人机器人的技术难点和应用情况
  13. 嵌入式开发日记(3)——利用Python接收并处理JY61传感器数据
  14. indexOf的用法
  15. 【opencv】图片拼接
  16. jenkins基础与gitlab代理自动构建
  17. OCR识别通过某瓣人机验证
  18. Java中实现十进制数转换为二进制的几种办法
  19. Activiti7-任务分配
  20. 用户体验是什么?如何把用户体验做到极致, 这里有答案

热门文章

  1. Win11输入法的选字框不见了怎么办?
  2. 提供 Android 酷炫的开屏动画 (awesome-opening-animation)
  3. 网购可到家门口的报亭提货了
  4. canvas轨迹运动, 利用向量实现点匀速运动
  5. 算法到底有没有价值观?快手给出了标准答案
  6. 逍遥模拟器安卓7.1 xposed安装
  7. 斐波那契数列+pyton
  8. python做交易软件_我用Python做了个量化交易工具!
  9. 【GISer小O】JAVA后台的小白之路(一)_2 ——分分合合三剑客
  10. java实现 腾讯人机验证 + 前端