iOS -- isa指针

news2024/11/25 4:35:54
  1. isa指针:isa指针是一个指向对象所属类或元类的指针。它决定了对象可以调用的方法和属性。isa指针在对象的结构中存在,并且在运行时会被自动设置。
  2. isa 指针,表示这个对象是一个什么类。而 Class 类型, 也就是 struct objc_class * ,这是苹果在下面的注释中写到的。这说明类本身也是一个对象。在类对象中的 isa 指向的类叫做“元类”,类方法就定义在元类中。总的来说就是,一个类可以有很多的实例,这些实例有着唯一的一个类对象,而这个类对象也有着唯一的一个元类。
  3. 在这里插入图片描述

在Objective-C中,每个对象都有一个isa指针,它指向该对象所属的类或元类。isa指针决定了对象可以调用的方法和属性。通过isa指针,Objective-C运行时可以在运行时动态地确定对象所属的类,并在该类或其父类中查找对应的方法实现。
下面是一些示例代码来说明isa指针的作用:

@interface MyClass : NSObject
- (void)myMethod;
@end

@implementation MyClass
- (void)myMethod {
    NSLog(@"MyClass's myMethod");
}
@end

int main() {
    MyClass *myObject = [[MyClass alloc] init];
    [myObject myMethod];
    return 0;
}

在上面的示例中,创建了一个名为MyClass的类,它继承自NSObjectMyClass类中定义了一个名为myMethod的方法。

当我们创建一个MyClass对象并调用myMethod方法时,实际上发生了以下过程:

  1. 分配内存并初始化MyClass对象。
  2. 运行时为该对象设置isa指针,使其指向MyClass的类对象。
  3. myObject上调用myMethod方法时,运行时首先通过isa指针找到MyClass的类对象。
  4. 运行时在类对象中查找名为myMethod的方法实现并执行。

通过这个过程,我们可以看到isa指针在动态确定对象所属的类的过程中起到了关键作用。它使得我们可以在运行时根据对象的实际类型来调用适当的方法。

isa,类对象,元类对象

OC的对象及其alloc和init。验证了OC对象底层是结构体,然后在alloc的方法调用栈的最后一个关键方法creatinstance中,有一个创建isa指针的方法。这篇,我们就先聊一聊isa指针。
我们知道,OC中的绝大部分对象,都是继承自NSObject(目前我已知的只有一个 NSProxy 类不继承自NSObject,它跟NSObject一样,是基类)。按住command键,跳进NSObject的头文件,就能看到下面的代码:

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

这就是NSObject的声明了,它只有一个isa指针,万物继承自NSObject,就有了自己的isa指针了。那这个isa到底有什么用呢?它究竟是个啥东西?

位域

在说isa之前,我们先了解一下[[共用体]]和[[位域]]这种技术。

在armv7、armv7s时代,由于是32位操作系统,苹果并没有对指针进行优化,实例对象的isa是直接指向类对象的。进入到arm64架构时代后isa占用8个字节,共计64位,如果只是单纯存一个指针太浪费,所以,苹果通过共用体技术,充分的让这64位存储了非常多的信息,不用再额外的开辟空间来存储,减少了内存开支,减少了内存的操作。下面我们具体看一下isa的结构。

isa的定义

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct{
        ISA_BITFIELD;  // defined in isa.h  说明在isa.h中
    };
#endif
};

里面有个ISA_BITFIELD,再看这个是怎么定义的:

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD                                                      \
      uintptr_t nonpointer        : 1;          //表明这个属性占一位,且从低位开始\
      uintptr_t has_assoc         : 1;          // 同上                       \
      uintptr_t has_cxx_dtor      : 1;                                       \
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
      uintptr_t magic             : 6;                                       \
      uintptr_t weakly_referenced : 1;                                       \
      uintptr_t deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
#   define RC_ONE   (1ULL<<45)
#   define RC_HALF  (1ULL<<18)

isa union共用体中各个位的含义

  • nonpointer 指示位,表示是否对isa指针开启指针优化,值为0表示纯isa指针 1表示不止是类对象的地址,isa中还包含了类信息、对象的引用计数等

  • has_assoc: 关联对象标志位,0没有,1存在(KVO的实现原理)

  • has_cxx_dtor :该对象是否有C++或者Objc的析构器,如果有析构函数,则需要做析构逻辑,如果没有,则可以更快的释放对象

  • shiftcls: 实际存储类指针的值。开启指针优化的情况下,在arm64架构中有33位用来存储类指针,也是基于此,不同的架构中,对于类指针的读取需要不同的操作,在32位时期,由于,由于未进行isa优化,isa是直接指向类对象的,在64位之后,需要用isa指针与上掩码(ISA_MASK)才能取到指针,这个指针指向类对象。

  • magic :用于调试器判断当前对象是真的对象还是没有初始化的空间

  • weakly_refrenced: 对象是否被指向或者曾经指向一个ARC的弱变量,没有弱引用的对象,可以更快的释放

  • dellocating :标志对象是否正在释放对象。ing表示进行时

  • has_sidetable_rc:当对象引用计数大于0时,则需要借用该变量存储进位。weak的实现原理,就是使用sidetables。后续讲到内存管理的时候会对此进行详细的讲解。

  • extra_rc:当表示该对象的引用计数值,实际上是引用计数值减1.例如,如果对象的引用计数为10,那么extra_rc为9,如果引用计数大于10,则需要使用到上面的has_sidetable_rc。

用64位存储了这么多的信息,相当的高效!!我当初知道这个点的时候,叹为观止!苹果真的把这种细节这种设计做到了极致。苹果的工程师们真他娘的都是人才,各个身怀绝技(也可能我作为井底之蛙,没有了解过这个技术)。

好,介绍过isa之后,接下来就该是实例对象、类对象、和元类对象了。

在arm64架构之后,isa通过shiftcls来指向类对象的。类对象也是个对象,也有isa指针,它的isa中的shiftcls是指向元类对象的。元类对象也有isa,它的shiftcls都指向根类的元类对象。 网上有一张非常经典的图来展示了对象和元类对象的关系(这幅图将贯穿大部分关于底层原理的博客内容)来看一下:
在这里插入图片描述

这个图用语言来描述一下,就是

  • 实例对象的isa指向的类对象,类对象的isa指向元类对象。元类对象的isa均指向基类的元类对象(基类的元类对象的isa指向自己)。需要特别注意,arm64架构后,isa不直接指向,需要先用掩码取出shift_cls指针,这个是实际的指向关系的指针。
  • 类对象和元类对象中有superclass指针,普通类对象的superclass指针指向父类的类对象,基类类对象的superclass指向nil。基础对象的元类对象的superclass指针指向父类的元类对象,基类的superclass指针指向父类的类对象。

写完这些我都不认识这个类字了。谨记这幅图,就能非常好的理解实例对象、类对象、元类对象之间的关系了。这个图画的非常好,在后面的runtime的消息转发流程中还会用到这幅图以及这些对象之间的关系。

为什么需要类对象和元类对象

那为啥要有类对象和元类对象呢?类对象和元类对象中都放着什么东西呢?

先说为什么。我们都知道,我们创建的类,有很多的属性、协议和方法,方法又分为实例方法和类方法。而这些方法的实现都是统一的,再调用的过程中,只是参数的值不同,所以这些方法存一份儿就够了,没必要在每个对象中都存一份。所以就有了类对象和元类对象。可以想一下平时写的方法调用的代码,假定Person类有一个实例方法叫-(void)instanceFunction,有个类方法+(void)classFunction。我们在调用的时候是这么调用的:

- (void)callFunctions{
    [person instanceFunction];     //使用实例对象来调用实例方法
    [Person classFunction];        //使用类名(其实就是类对象)调用类方法
}

可以很明显的看出,方法调用者的不同。而这个不同就是由类对象、元类对象、isa来实现的。类对象中,存储了这个类的属性、协议和实例方法。元类对象中存储了这个类的类方法。在方法调用时,实例方法通过这个实例对象的isa找到这个类的对象,然后在类对象中查找这个方法。类方法通过类对象的isa找到这个类的元类对象,在元类对象中查找这个方法。通过这样的描述,结合上面的图,就能很好的理解isa指针、类对象和元类对象了。

好,简单的来总结一下今天的内容。主要是理清实例对象、类对象、元类对象之间的关系,要记住那副图,保证自己能完整的复述出他们之间的关系。isa就相当于纽带,将他们串联了起来。在最后提到了,类对象和元类对象是存储属性、协议和方法的,我们会在runtime中,具体的讲解这些信息是如何存储的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/639074.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

XML 的命名空间及其在OPCUA中的应用

为了防止不同XML 使用的名称冲突&#xff0c;XML 规范中规定的命名空间&#xff0c;平时编写单一命名空间的XML 文档&#xff0c;没有过多地注意XML 命名空间的细节。当开发OPCUA 信息模型时&#xff0c;被命名空间搞得云里雾里。为此&#xff0c;做了一个笔记。 URI(Uniform R…

Vue3_ElementPlus_简单增删改查(2023)

Vue3&#xff0c;Element Plus简单增删改查 代码&#xff1a;https://github.com/xiaoming12318/Vue3_ElementPlus_CRUD.git 环境&#xff1a; Visual Studio Code Node.js 16.0或更高版本&#xff0c;https://nodejs.org/en axios 快速上手&#xff1a; 如果已经有16.0及…

Vue单文件组件

单文件组件 单文件组件是在开发中用的比较多的&#xff0c;它的后缀都是.vue结尾的 既然是.vue结尾&#xff0c;那么直接给浏览器是不能运行的&#xff0c;.vue文件是vue团队打造的特殊文件&#xff0c;想让.vue文件让浏览器识别并且运行&#xff0c;需要对它进行处理加工成纯…

5款大厂设计师都在用的网页设计工具

本文收集了5款大厂设计师使用的几种流行易用的网页设计工具&#xff0c;其中一个可以AI自动生成设计稿&#xff0c;非常的方便&#xff0c;相信一定有一个适合你的网页设计工具。 1.即时设计 即时设计是一款免费的在线 UI 设计工具&#xff0c;无系统限制&#xff0c;浏览器打…

三个原则判定电源环路稳定性

1 环路稳定性评价指标 衡量开关电源稳定性的指标是相位裕度和增益裕度。同时穿越频率&#xff0c;也应作为一个参考指标。 (1) 相位裕度是指&#xff1a;增益降到0dB时所对应的相位。 (2) 增益裕度是指&#xff1a;相位为0deg时所对应的增益大小(实际是衰减)。 (3) 穿越频率…

DVWA下载、安装及使用教程,网络安全小白必看!

DVWA是一款基于PHP和mysql开发的web靶场练习平台&#xff0c;集成了常见的Web漏洞。旨在为安全人员测试自己的专业技能和工具提供合法的环境&#xff0c;帮助web开发者更好的理解web应用安全防范的过程&#xff1b; 一、DVMA介绍 DVWA官网 (opens new window)DVWA Github (ope…

springboot配置文件中的巨坑!!

问题 application.yml test:password1: 030030password2: 030030使用此配置的bean Component public class Test {Value("${test.password1}")private String password1;Value("${test.password2}")private String password2;PostConstructpublic void …

企业微信建设代开发应用的基本流程及实现

一、企业微信代开发应用的基本流程 企业微信中除了系统提供的应用以及上架应用商店的第三方应用外&#xff0c;也可以使用自己开发的应用&#xff0c;不过多数企业都不具备开发能力&#xff0c;只能采用代开发的形式进行定制。就给大家分享一下企业微信代开发应用的基本流程&a…

java八股面试文(带答案,万字总结,精心打磨,建议收藏)堪称2023最强

前言 2023秋招即将来临&#xff0c;很多同学会问Java面试八股文有必要背吗&#xff1f; 我的回答是&#xff1a;很有必要。你可以讨厌这种模式&#xff0c;但你一定要去背&#xff0c;因为不背你就进不了大厂。 国内的互联网面试&#xff0c;恐怕是现存的、最接近科举考试的…

【Java项目】不使用ES实现关键词搜索问题

文章目录 需求解决思路基本设计查询流程插入流程修改流程删除流程 优化思路总结 需求 ok&#xff0c;这个需求是我提的&#xff0c;然后我问了我的一位杭州的朋友&#xff0c;然后我们最后一起敲定这个方法。 我的项目有一个根据关键字进行商品名称的搜索功能&#xff0c;用户…

安卓期末考试知识总结

文章目录 第一章&#xff1a;Android基础入门习题总结重点知识 第二章&#xff1a;Android常见桌面布局&第三章&#xff1a;Android常见界面控件知识总结习题总结 第一章&#xff1a;Android基础入门 习题总结 Android系统采用分层架构&#xff0c;由高到低分为4层&#…

MySQL数据库 --- 运维篇

一、日志 1.1、错误日志 错误日志是 MySQL 中最重要的日志之一&#xff0c;它记录了当 mysqld 启动和停止时&#xff0c;以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时&#xff0c;建议首先查看此日志。 该日志是默认开启的…

实训笔记6.12

实训笔记6.12 6.12一、座右铭二、知识回顾2.1 面向对象的两大核心概念&#xff1a;类和对象2.2 面向对象的三大特征封装性继承性多态性-必须在继承之上抽象性 2.3 面向对象的常用关键字2.4 Java设计模式中适配器模式2.4.1 接口适配器2.4.2 类适配器2.4.3 对象适配器 三、Java常…

Linux基础知识3

Linux基础知识 适合有Linux基础的人群进行复习。 禁止转载&#xff01; 用户与用户组管理 Linux系统下的3类用户和功能&#xff1b; 答&#xff1a; root用户&#xff08;或称根用户、超级用户&#xff09;&#xff1a;Linux的内置用户&#xff0c;权限最高&#xff0c;具有…

wps安装提示nsis error

1.安装时弹出「NSIS error」错误框&#xff0c;无法安装。 此问题为一般为安装包损坏导致&#xff0c;可重新下载安装包尝试安装。 我遇到的提示也是这个。文件损坏。但是换了绿色U盘&#xff08;格式是FAT32&#xff09;复制过去就能安装。 之前用白色U盘&#xff08;格式是N…

一学就会-----链表的回文结构

文章目录 题目描述思路代码示例 题目描述 对于一个链表&#xff0c;请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法&#xff0c;判断其是否为回文结构。 给定一个链表的头指针A&#xff0c;请返回一个bool值&#xff0c;代表其是否为回文结构。保证链表长度小于等于90…

1.1 搭建Scala开发环境

一、Windows上安装Scala &#xff08;一&#xff09;到Scala官网下载Scala Scala2.13.10下载网址&#xff1a;https://www.scala-lang.org/download/2.13.10.html 单击【scala-2.13.10.msi】超链接&#xff0c;将scala安装程序下载到本地 &#xff08;二&#xff09;安装…

Atcoder Beginner Contest 305

A - Water Station AC代码&#xff1a; #include<iostream> #include<algorithm> #include<cstring> using namespace std; int main() {int n;cin>>n;int a,b;for(int in;;i){if(i%50){ai;break;}}for(int in;;i--){if(i%50){bi;break;}}if(a-n<…

【Linux学习】多线程——线程池 | 单例模式

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 线程池 | 单例模式 一、 线程池1.1 Thread.hpp1.2 ThreadPool.hpp1.3 main.cpp1.4 RAII方式加锁 …

苹果的Safari私人浏览现在会自动删除URL中的跟踪参数

苹果将对Safari私人浏览器进行重大更新&#xff0c;为用户提供更好的保护&#xff0c;防止他们在浏览网页时被第三方跟踪。 苹果公司表示:“先进的追踪和指纹保护功能可以进一步防止网站利用最新技术追踪或识别用户的设备。” “隐私浏览现在在不使用时锁定&#xff0c;允许用…