type
status
date
slug
summary
tags
category
icon
password
我们经常需要在开发中判定某一个类,比如下面场景:
- 判定在某一个页面:
isMemberOfClass
来指定只有在某页面下的操作。
- 判断是否某个类,用于容错,这很常见。
这些涉及到类的判定的,我们下面会从一个关键字和两个方法去阐述。
super
关键字:调用父类方法的关键字
isMemberOfClass
方法:判断某个instance(class)是否是对应的class(meta-class)对象
isKindOfClass
方法:判断某个instance(class)是否是对应的class(meta-class)继承体系下的对象。
除了,需要关注本文讲的内容。还需关注的是,本文将iOS底层挖掘的方式大致都展现了。
一、super
super
平时开发中,调用的非常频繁,在viewcontroller
以及view
的生命各个周期方法,我们都会先调用父类的对应实现。下面我们根据实例,代码在这儿。去分析
super
的含义。我们定义下面两个有继承关系的类:
下面是调用代码:
输出日志:
- [BFPerson eat]
1.1 如何分析
我们下面将会通过各种方式来逐一对
super
进行剖析。1.1.1 C++代码分析
先将代码重写为C++代码
重写后,下面是
-[BFBoy eat]
函数的实现(删去了类型转换):从上面转换我们可以初步看出:
[super eat]
转换后调用了objc_msgSendSuper
类的函数,并且其参数比较陌生。是一个结构体,其含义似乎表示的是super
结构体。当然,我们从之前历次的分析来看,重写其实并不完全是运行时的行为表现,所以,这种方式仅做参考。
1.1.2 Developer Document登场
之前我们在分析各种各样的问题的时候,其实该方法,或者该工具一直没有正式登场。
下面我们在Xcode中,⌘+⇧+0 调出开发文档。
并在其中搜索上一步提到的
objc_msgSendSuper
。![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2F3ac0d810-5cc2-432c-a9ce-a50247304863%2FUntitled.png?table=block&id=bdeb09db-180e-4064-b8ab-7ecdf6e917e6&t=bdeb09db-180e-4064-b8ab-7ecdf6e917e6&width=816&cache=v2)
以上是,苹果开发文档给出的说明,权威清晰。缺点是,有时候文档并没有说明或者泛泛而谈,甚至不知所云。
1.1.3 源码
同样的,objc 源码也是我们找定义、找方法、找逻辑的最佳选择。
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2F8bcb1417-ba26-423d-b776-2955819801ba%2FUntitled.png?table=block&id=786e8b5b-5ea4-4d02-b875-958599a3cf3e&t=786e8b5b-5ea4-4d02-b875-958599a3cf3e&width=768&cache=v2)
这种方式,只要获取的源码是最新的,其对本质的还原度,最直接、还原度最高。缺点是,阅读源码费时费力费脑。
但阅读源码是基本功,要炉火纯青。
1.1.4 LLDB调试
以上都是从文档或者未运行的转译代码中,对代码本质的挖掘,如果以上过程能完成,基本对本质了解已经七七八八。
但是,OC是一门动态性强大的语言,所以,一切以运行时为准。
我们还需要观察运行时的状态。
至于如何运用LLDB进行调试,可以查看待补-iOS调试。
1.1.5 LLVM中间代码分析
这是一种全新的方式,是在编译过程中,产生的中间代码,来对中间代码进行剖析。
那么编译过程是如何产生中间代码的?
如下图:
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2F4c7abd03-9ba9-4078-ab56-869771d2a822%2FUntitled.png?table=block&id=3831c205-cae3-4ce1-af2f-cc8cf5eb6703&t=3831c205-cae3-4ce1-af2f-cc8cf5eb6703&width=816&cache=v2)
当然,有了中间代码,我们还要学会看,可参考官方文档。
以下是一些常用的语法:
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2F5537c618-46ef-4983-93fd-0a776e4e99f1%2FUntitled.png?table=block&id=e6459818-3b65-4e5b-80af-1b46cf43d50c&t=e6459818-3b65-4e5b-80af-1b46cf43d50c&width=816&cache=v2)
1.1.6 汇编分析
有时候,苹果没有给出文档,也无相关源码,甚至Debug时,也是毫无头绪,我们可以通过汇编指令级别的分析,来管中窥豹,或许能发现个所以然。
1.1.6.1 Perform Action
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2F9e41b526-885b-4d71-a4b3-34c69aa752ef%2FUntitled.png?table=block&id=8cfabdad-d658-4cdd-9626-57773574ab03&t=8cfabdad-d658-4cdd-9626-57773574ab03&width=480&cache=v2)
下面是对应的汇编源码:
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2Ffaaa2660-998a-4f4e-81a6-49ae3e43090b%2FUntitled.png?table=block&id=52f5e417-d674-4825-8e44-d18c9bc8b1e5&t=52f5e417-d674-4825-8e44-d18c9bc8b1e5&width=528&cache=v2)
1.1.6.2 Debug Workflow
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2F6f2be4b0-a820-4c0e-81ad-3d3aa6bbd1a8%2FUntitled.png?table=block&id=fddd510c-c133-482b-81b7-ff78c160ce89&t=fddd510c-c133-482b-81b7-ff78c160ce89&width=528&cache=v2)
下面是调试时的汇编指令:
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2Fa2192011-7dcf-40bc-880b-95b38c35964a%2FUntitled.png?table=block&id=e7ba07f9-3fa6-4ca1-925e-10ca76c052b1&t=e7ba07f9-3fa6-4ca1-925e-10ca76c052b1&width=768&cache=v2)
结合上面两种汇编方式查看,我们最终确定:
super
在底层,最终调用的方法是:objc_msgSendSuper2
。1.2 super
的本质
经过上面层层剥开,我们现在能确认
objc_msgSendSuper2
,是理解super
的关键。而
objc_msgSendSuper2
两个参数,对我们的理解又至关重要:其中
objc_super
:根据上面C++重写后的代码:
receiver
就是self
本身,即BFBoy
实例对象boy,它表示消息的接收者仍然是boy,即仍然是子类对象。
super_class
为BFBoy
的父类BFPeron
,它表示,要从父类开始查找对应的方法。
综上所述,总结为下图:
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2F66f3362e-2244-486e-81c4-18ed2a64456f%2FUntitled.png?table=block&id=1bc8248a-a7d8-4c87-ac90-21b0b6d40155&t=1bc8248a-a7d8-4c87-ac90-21b0b6d40155&width=864&cache=v2)
1.3 小试身手—实例测试
在了解了
super
对应的原理之后,我们就看一个小实例。在
BFBoy
的初始化方法中,上面打印的分别是什么?结果如下:
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2F24d432dd-69e9-4dc7-8605-50af23aede76%2FUntitled.png?table=block&id=5d5527f0-a9e1-4af2-982c-437504a13ca5&t=5d5527f0-a9e1-4af2-982c-437504a13ca5&width=536&cache=v2)
和你预想的一致吗?我们仍然对这个进行一些分析:
super
相关的调用转化为objc_msgSendSuper2
调用;
objc_msgSendSuper2
开始从BFPerson
查找class/superclass
方法;
- 一直找到
NSObject
,调用NSObject
的class/superclass
方法;我们从objc源码中找到下面实现:
假如父类
BFPerson
未实现的方法,在NSObject
实现了,而class/superclass
中的self
,就是BFBoy
实例对象boy本身,那么上面的结果你明白了吗?二、类的判定
2.1 isMemberOfClass
从
NSObject.mm
源码中得到:从源码可以得出:
instance对象
:判断对应的class对象
是否和传入的对象
相同。
class对象
:判断对应的meta-class对象
是否和传入的对象
相同。
- 传入的对象,
intance对象
、class对象
、meta-class
对象都可以。
2.2 isKindOfClass
instance对象
:判断对应的class对象及其父类对象
是否和传入的对象
相同。
class对象
:判断对应的meta-class对象
及其父类对象是否和传入的对象
相同。
- 传入的对象,
intance对象
、class对象
、meta-class
对象都可以。
2.3 实例
上面的输出,有一行需要着重指出:
翻译一下:NSObject类的元类对象,及其该元类对象的父类对象与NSObject类对象相等吗?
第一反应,不相等,元类对象怎么会和类对象相等。但是其结果为1。
如下图:
- NSObject元类对象在其寻找父类,找到根元类后,会指向类对象,这是一个陷阱。
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2Fd1b21be2-1912-47c6-9577-fe8160d4e04c%2FUntitled.png?table=block&id=a889fbbf-ed5c-48bb-9e52-3954b775a2cd&t=a889fbbf-ed5c-48bb-9e52-3954b775a2cd&width=528&cache=v2)
三、总结
3.1 super
[super message]的底层实现。
- 消息接收者仍然是子类对象
- 从父类开始查找方法的实现
3.2 类的判定
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2Fec9f1a02-995b-4629-8c9a-ee342f1a4211%2FUntitled.png?table=block&id=98fa78b6-55a7-444a-8718-b2a1e8dcf57d&t=98fa78b6-55a7-444a-8718-b2a1e8dcf57d&width=864&cache=v2)
![notion image](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Ff283ca8c-3a00-40dd-87c9-43c248d44a31%2Fcfb4c4fe-b4a8-4e66-8a67-6b8dafb04cb0%2FUntitled.png?table=block&id=ab9625a2-f15d-4d4f-8995-ff910854aeae&t=ab9625a2-f15d-4d4f-8995-ff910854aeae&width=816&cache=v2)
参考
链接
示例代码