iOS-class方法和objc_getClass方法

iOS-class方法和objc_getClass方法根据上一篇博客iOS-class、object_getClass、objc_getClass、objc_getMetaClass区别的研究发现,qi’s

大家好,又见面了,我是你们的朋友全栈君。

根据上一篇博客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的对象模型图

iOS-class方法和objc_getClass方法

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

iOS-class方法和objc_getClass方法

实例对象(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);

输出结果:

iOS-class方法和objc_getClass方法

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);

输出结果:

iOS-class方法和objc_getClass方法

当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;  // 类的版本信息,默认为0
     long 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);

输出结果:

iOS-class方法和objc_getClass方法

 当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);

输出结果:

iOS-class方法和objc_getClass方法

当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);

输出结果:

iOS-class方法和objc_getClass方法

当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方法区别

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/147798.html原文链接:https://javaforall.net

(0)
上一篇 2022年6月29日 下午8:46
下一篇 2022年6月29日 下午8:46


相关推荐

  • hive安装需要安装mysql区别_Hive安装

    hive安装需要安装mysql区别_Hive安装一 Hive 安装环境装备安装 JDK 安装 hadoop 集群二 下载 Hive 安装包根据需要下载相应的版本 这里以 hive 1 2 2 为例 三 Hive 安装包解压 1 根据 hadoop 集群的系统资源消耗情况 选择进程消耗比较小的进行安装 这里以 node2 节点为例 hive 安装包通过 xshell 中的 xftp 工具上传到 node2 上 2 解压 hive 安装包 1 把 hive 的压缩安装包解压到 opt bigdata

    2026年3月19日
    2
  • 瀑布模型&快速原型模型

    瀑布模型&快速原型模型一 瀑布模型 1 1 什么是瀑布模型瀑布模型将软件生命周期划分为软件计划 需求分析 软件设计 程序编码 软件测试 运行维护等基本活动 并且规定了他们自上而下 相互衔接的固定顺序 如同瀑布流水 逐级下落 瀑布模型是最早出现的软件开发模型 在软件工程中占有特别重要的地位 它提供了软件开发的基本框架 其过程是从上一项活动接收该项活动的工作对象作为输入 利用这一输入实施该项活动应完成的内容给出该项活动的工作成果 并作为输出传给下一项活动 对于经常变化的项目而言 瀑布模型毫无价值 1 2 特点 1 阶段间具

    2026年3月18日
    2
  • 实现一个单向链表_java链表添加

    实现一个单向链表_java链表添加链表是常用的一种数据结构,如何创建链表、增、删、查找等功能是本文讨论的内容。首先,链表需要两个指针,一个是头指针是固定不变的,一个是移动变化的指针。(1)为什么要头指针?原因是单向列表中的数据结构包含的只有下一个数据的指针,这样就说明了,单向链表是不可逆向进行操作。所有的操作都需要正向去操作。这时我们必须要知道第一个数据的地址,才能从第一个数据往后访问其他数据。(2)可移动的指针的作用有两个,一个…

    2025年7月25日
    2
  • numpy的astype函数

    numpy的astype函数astype函数用于array中数值类型转换

    2022年5月27日
    99
  • Unity HLOD System[通俗易懂]

    Unity HLOD System[通俗易懂]1.1HLODSystem简介首先,HLODSystem主要的目标是为了减少DrawCall。然后,进行更多的Batch批处理。其次,减少面数和纹理,这样我们相应地节省了内存,并提升了加载时间。HLODSystem只针对当前所在的地方进行加载,它会流式加载网格和纹理,在后台进行异步的操作。本次HLOD是基于官方AutoLOD代码的扩展和改进制作出来了的,链接:https://github.com/Unity-Technologies/AutoLOD,链接里有一篇官方的文章,…

    2025年8月15日
    6
  • ubuntu查看系统版本

    ubuntu查看系统版本下面写一下查看当前 Linux 系统的版本的方法一 使用命令 cat proc version 查看 linux 版本号 Linuxversion 4 0 99 generic buildd lgw01 amd64 007 GCC 版本号 gccversion9 3 0Ubuntu 版本号 ubuntu1 20 04 二 使用命令 uname a 查看显示 linux 的内核版本和系统是多少位的 X86 64 代表系统是 64 位的三 使用命令 lsb r

    2026年3月20日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号