【iOS】isKindOfClass和isMemberOfClass方法

news2024/11/25 13:35:39

前言

这个归根结底还是在考察我们对isa走向图和类的继承的理解,也就是苹果官方这幅图:
在这里插入图片描述

接下来的函数调用流程请参考这张图。

1 isKindOfClass方法

1.1 objc_opt_isKindOfClass C函数

查看源码可发现,无论是谁调用isKindOfClass方法都会进入这个C函数。(这个C函数位于NSObjective.mm

// Calls [obj isKindOfClass]
// 当obj调用isKindOfClass时,objc_opt_isKindOfClass会被触发
// obj是一个id类型,id是一个objc_object结构体指针,意味着,传进来的可以是时类,也可以是类的实例对象
// otherClass就是isKindOfClass的参数,我们当初传进去的cls
BOOL objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
    if (slowpath(!obj)) return NO;
    
    Class cls = obj->getIsa();	 // 此处的cls仅是obj的第一个isa
    if (fastpath(!cls->hasCustomCore())) {
        
        // otherClass 从obj的ISA开始,依次和ISA的父类比较,直到找到或者父类为nil结束
		// 当父类为nil意味着最后一个和otherClass比较的是NSObject根类。
        for (Class tcls = cls; tcls; tcls = tcls->superclass) {
            if (tcls == otherClass) return YES;
        }
        return NO;
    }
#endif
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}

可知:

  1. 一切皆从调用者objisa开始,然后顺着superclass走下去,直到找到clssuperclassnil结束。
  2. superclassnil,意味着最后的根类NSObject也不是cls,返回flase

1.2 类SubClass调用+ (BOOL)isKinsOfClass:(Class)cls

流程:

  1. 从类的isa——元类开始,判断它不是cls
  2. 如果是,返回true
  3. 如果不是,继续用元类的superclasscls比较,看是不是cls
  4. 直到根类NSObject也比较完。

判断顺序: SubClassMetaClass->MetaClass->...->RootMetaClass->NSObject

总结:

  • 判断cls是不是 元类->父类的元类->父父类的元类->…->根元类->NSObject (元类的superclass继承链)其中一个。
  • cls 传除NSObject.class外的任意类对象均为false

1.3 元类MetaClass 调用+ (BOOL)isKinsOfClass:(Class)cls

流程:

  1. MetaClassISA 指向 RootMetaClass ,所以从 RootMetaClass 开始比较判断是不是我们传入的cls;
  2. 如果不是,再看根类NSObject是不是,如果NSObject也不是,就彻底没有了,返回false

判断顺序:MetaClassRootMetaClass->NSObject

总结:

  • 判断cls是不是 根元类->NSObject 中的任意一个。

1.4 对象obj 调用- (BOOL)isKinsOfClass:(Class)cls

流程:

  1. isa指向的类对象开始,判断是不是cls
  2. 如果不是,看类对象的父类,逐级判断是不是cls
  3. 直到找到返回true,或者判断到NSObject依然不是,返回false结束。

判断顺序: objectSubClass -> SubClass ->...->NSObject

总结:

  • 判断cls是不是 类对象->父类->…->NSObject (superclass继承链)其中一个。

2 isMemberOfClass

2.1 类对象SubClass调用+ (BOOL)isMemberOfClass

源码:

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

不用像isKindOfClass循环直到找到或nil,他只要比较cls是不是我当前的isa指向,是返回true,不是返回false。

判断:SubClassMetaClass

2.2 元类MetaClass 调用+ (BOOL)isMemberOfClass

因为元类的isa只指向根元类NSObejct ,所以除了NSObject的类SubClass以外,传入任何类对象也都是false。

验证传入NSObject的类SubClass的结果:

void demo(void) {
//    BOOL re1 = [[NSObject class] isKindOfClass:[NSObject class]];
    Class rootMetaClass = object_getClass([NSObject class]);
    
    NSLog(@"%d", [[NSObject class] isMemberOfClass:rootMetaClass]);
}

结果:
在这里插入图片描述

2.3 对象obj调用 -(BOOL)isMemberofClass:(Class)clss

- (BOOL)isMemberOfClass:(Class)cls 底层源码:

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}
- (Class)class {
    return object_getClass(self); // 获取当前的isa指向的类
}

只要判断对象的isa,也就是图中的SubClass是不是我们传入的cls。

3. 测试

void demo(void) {
    BOOL f1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
    BOOL f2 = [(id)[MyClass class] isKindOfClass:[MyClass class]];
    BOOL f3 = [(id)[MySuperClass class] isKindOfClass:[MySuperClass class]];
    BOOL f4 = [(id)[MyClass class] isKindOfClass:[MySuperClass class]];
    
    BOOL f5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
    BOOL f6 = [(id)[MyClass alloc] isKindOfClass:[NSObject class]];
    BOOL f7 = [(id)[MySuperClass alloc] isKindOfClass:[NSObject class]];
    
    NSLog(@"NSObjectClass ISKindOf NSObjectClass:%d", f1);
    NSLog(@"MyClassClass ISKindOf MyClassClass:%d", f2);
    NSLog(@"MySuperClassClass ISKindOf MySuperCassClass:%d", f3);
    NSLog(@"MyClassClass ISKindOf MySuperClassClass:%d", f4);
    NSLog(@"NSObjectObj ISKindOf NSObjectClass:%d", f5);
    NSLog(@"MyClassObj ISKindOf NSObjectClass:%d", f6);
    NSLog(@"MySuperClassObj ISKindOf NSObjectClass:%d", f7);
    
}

测试结果:
在这里插入图片描述

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

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

相关文章

系统学习Linux-MySQL服务基础(一)

一、MySQL服务概述 什么是数据库? 将大量数据保存起来,通过计算机加工而成的可以进行高效访问的数据集合 数据库是存储、管理和操作组织化数据的软件系统 数据库能干什么? 企业应用存放用户数据、管理企业数据金融行业存储分析客户的财务…

Stable Diffusion在各种显卡上的加速方式测试,最高可以提速211.2%

Stable Diffusion是一种基于扩散模型的图像生成技术,能够从文本生成高质量的图像,适用于CG,插图和高分辨率壁纸等领域。 但是它计算过程复杂,使得它的生成速度较慢。所以研究人员就创造了各种提高其速度的方式,比如Xf…

Springboot读取配置的一些方式

从配置文件中获取属性应该是SpringBoot开发中最为常用的功能之一,但就是这么常用的功能,仍然有很多开发者在这个方面踩坑。 下面整理了几种获取配置属性的方式,弄清配置加载、读取的底层原理,一旦出现问题可以分析。 以下示例源…

Linux基础开发工具之Linux编译器的使用(gcc/g++)

目录 前言 1.背景知识介绍 2.预处理阶段 3.编译阶段 4.汇编阶段 5.链接过程 5.1 函数库 5.1.1 静态库和动态库 5.2 链接过程的具体内容 总结 前言 大家好呀,许久没给大家更新了,对于我们在Linux环境下编程,之前小编只是给大家介绍…

Ubuntu安装JDK与IntelliJ IDEA

目录 前言 Ubuntu安装JDK 1、更新软件包列表 2、安装OpenJDK 3、验证安装 Ubuntu安装IntelliJ IDEA 1、下载 IntelliJ IDEA 2、解压缩 IntelliJ IDEA 安装包 3、移动 IntelliJ IDEA 到安装目录 4、启动 IntelliJ IDEA 前言 APT(Advanced Package Too…

react 在build读取env 数据

默认会读取.env 文件 npm install dotenv --save npm install dotenv-cli --save-dev例如读取.env.test "build:test": "dotenv -e .env.test react-app-rewired build",.env.test REACT_APP_CURRENTMODE devREACT_APP_Public_Path "https://baid…

VUE中的生命周期、每个生命周期可以干什么

生命周期 就VUE来说就是一个程序的即将创建到销毁的一个过程,也就是vm对象实例从创建到最终销毁的过程。 VUE生命周期4个阶段8个钩子函数(到某一阶段自动调用的函数) 1.初始阶段(虚拟的DOM生成) beforeCreate() 初始化事件对象和生命周期…

width: calc(~“100% - 267px“);动态css 调样式

.result-filtering {color: #8b8b8b;display: flex;// width: 82.6%;width: calc(~"100% - 267px");}

证书文件无法生成.p12

做好的证书文件在生成.p12文件的过程中遇到了.p12选项置灰且无法选择并导出的情况 解决办法 起初认为生成的空白 CertificateSigningRequest 有问题,反反复复尝试几次制作后均无效; 而后发现问题出在了钥匙串访问的选项问题上 ... 将顶部菜单 tab 由"所有选项"切换至…

ActivityWatch配置跨平台同步(没弄完)

安装完后马上给你来个下马威&#xff1a; 具体内容如下&#xff1a; Traceback (most recent call last): File "aw_qt\__main__.py", line 3, in <module> File "click\core.py", line 1130, in __call__ File "click\core.py", l…

docker制作compose

第一步&#xff0c;先了解Compose是什么&#xff1f; Compose 项目是 Docker 官方的开源项目&#xff0c;负责实现对 Docker 容器集群的快速编排。 Compose有两个重要的概念 1.项目 &#xff1a;由一组关联的应用容器组成的一个完整业务单元&#xff0c;在docker-compose.ym…

最受欢迎的8种编程语言解析_kaic

国内目前最受欢迎的8种编程语言解析 在过去的 17 个月&#xff08;2022 年 1 月至 2023 年 5 月&#xff09;时间里&#xff0c;DevJobsScanner 通过分析超 1400 万个开发人员职位&#xff0c;并从中筛选了有明确编程语言需求的职位&#xff0c;得出了在 2023 年需求量最大的 …

Socket基本原理详解

socket的概念 故事要从一个插头说起。 插头与插座 当我将插头插入插座&#xff0c;那看起来就像是将两者连起来了。 风扇与电力系统建立"连接" 而插座的英文&#xff0c;又叫socket。 巧了&#xff0c;我们程序员搞网络编程时也会用到一个叫socket的东西。 其实两者…

[算法通关村] 1.1 单向链表的创建

各位读者朋友们&#xff0c; 从今天开始&#xff0c;我将通过博文的形式&#xff0c;概述数据结构中应知必会的基本算法&#xff0c; 由于我更加熟悉 Java 语言&#xff0c;所以全程使用 Java 语言进行叙述&#xff0c; 如果您发现了文章中的错误&#xff0c;请您不吝赐教。 什…

HCIP——OSPF综合实验

OSPF实验 一、实验拓扑二、实验要求三、实验思路四、实验步骤1、配置接口IP地址以及环回2、配置缺省路由3、配置MGRE环境4、配置OSPF5、修改网络类型6、重发布7、配置汇总空接口防环8、配置特殊区域&#xff1a;9、配置NAT环境10、加快收敛11、配置接口认证12、测试 一、实验拓…

ModHeader插件

ModHeader浏览器插件下载装载地址&#xff1a;&#xff08;microsoftedge&#xff09;ModHeader - Modify HTTP headers - Microsoft Edge Addonshttps://microsoftedge.microsoft.com/addons/detail/modheader-modify-http-h/opgbiafapkbbnbnjcdomjaghbckfkglc?refidbingshor…

MySQL 主从复制的认识 2023.07.23

一、理解MySQL主从复制原理 1、概念&#xff1a;主从复制是用来建立一个和 主数据库完全一样的数据库环境称为从数据库&#xff1b;主数据库一般是准实时的业务数据库。 2、作用&#xff1a;灾备、数据分布、负载平衡、读写分离、提高并发能力 3、原理图 4、具体步骤 (1) M…

微服务远程调用openFeign简单回顾

目录 一. OpenFeign简介 二. OpenFeign原理 演示使用 provider模块 消费者模块 配置全局feign日志 示例源代码: 一. OpenFeign简介 OpenFeign是SpringCloud服务调用中间件&#xff0c;可以帮助代理服务API接口。并且可以解析SpringMVC的RequestMapping注解下的接口&#x…

生物信息学_玉泉路_课堂笔记_04 第四章 高通量测序技术与 数据分析

&#x1f345; 课程&#xff1a;生物信息学_玉泉路_课堂笔记 中科院_2022秋季课 第一学期 &#x1f345; 个人笔记使用 &#x1f345; 2023/7/19 测序技术 鸟枪法测序 全球测试仪的使用情况 边合成边测序 深颜色是加的接头 adapter 浅颜色的是要测的片段 insert ① 重叠的情…

【iOS】动态链接器dyld

参考&#xff1a;认识 dyld &#xff1a;动态链接器 dyld简介 dyld&#xff08;Dynamic Linker&#xff09;是 macOS 和 iOS 系统中的动态链接器&#xff0c;它是负责在运行时加载和链接动态共享库&#xff08;dylib&#xff09;或可执行文件的组件。在 macOS 系统中&#xf…