> For the complete documentation index, see [llms.txt](https://ryukiedev.gitbook.io/wiki/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ryukiedev.gitbook.io/wiki/zhi-shi-dian-shu-li/yi-tao-ios-di-ceng-shi-juan.md).

# 08 一套iOS底层试卷

> [一套iOS底层试卷](https://juejin.cn/post/6983175020340051976)

## 一、选择题 ⚠️ 有单选有多选哦⚠️

### 1.1 在LP64下,一个指针的有多少个字节

* [ ] A: 4
* [ ] \[X] B: 8
* [ ] C: 16
* [ ] D: 64

### 1.2 一个实例对象的内存结构存在哪些元素

* \[X] A:成员变量
* \[X] B: supClass
* \[X] C: cache\_t
* \[X] D: bit

> A

### 1.3 下面sizeof(struct3) 大小等于

```cpp
struct Struct1 {
    char b;// 1
    int c; // 4
    double a; // 8
    short d; // 2
}struct1;

struct Struct2 {
    double a;
    int b;
    char c;
    short d;
}struct2;

struct Struct3 {
    double a;
    int b;
    char c;
    struct Struct1 str1;
    short d;
    int e;
    struct Struct2 str2;
}struct3;
```

* [ ] A: 48
* [ ] \[X] B: 56
* [ ] C: 64
* [ ] D: 72

> C

### 1.4 下列代码: re1 re2 re3 re4 re5 re6 re7 re8输出结果

```
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];     
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];   
BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];     
BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];  
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);

BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];      
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];    
BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];     
BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];   
NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
```

* [ ] A: 1011 1111
* [ ] B: 1100 1011
* [ ] \[X] C: 1000 1111
* [ ] D: 1101 1111

### 1.5 (x + 7) & \~7 这个算法是几字节对齐

* [ ] A: 7
* [ ] \[X] B: 8
* [ ] C: 14
* [ ] D: 16

### 1.6 判断下列数据结构大小

```cpp
union kc_t {
    uintptr_t bits;// 8
    struct {
        int a;// 4
        char b;// 1
    };
}
```

* [ ] \[X] A: 8
* [ ] B: 12
* [ ] C: 13
* [ ] D: 16

### 1.7 元类的 isa 指向谁, 根元类的父类是谁

* [ ] A: 自己 , 根元类
* [ ] \[B] B: 自己 , NSObject
* [ ] C: 根元类 , 根元类
* [ ] \[X] D: 根元类 , NSObject

### 1.8 查找方法缓存的时候发现是乱序的, 为什么? 哈希冲突怎么解决的

* [ ] A: 哈希函数原因 , 不解决
* [ ] \[X] B: 哈希函数原因 , 再哈希
* [ ] C: 他存他的我也布吉岛 , 再哈希
* [ ] D: 他乱由他乱,清风过山岗 , 不解决

### 1.9 消息的流程是

* \[X] A: 先从缓存快速查找
* \[X] B: 慢速递归查找methodlist (自己的和父类的,直到父类为nil)
* \[X] C: 动态方法决议
* \[X] D: 消息转发流程

### 1.10 类方法动态方法决议为什么在后面还要实现 resolveInstanceMethod

* [ ] A: 类方法存在元类(以对象方法形式存在), 元类的父类最终是 NSObject 所以我们可以通过resolveInstanceMethod 防止 NSObject 中实现了对象方法!
* [ ] B: 因为在oc的底层最终还是对象方法存在
* [ ] \[X] C: 类方法存在元类以对象方法形式存在.
* [ ] D: 咸吃萝卜,淡操心! 苹果瞎写的 不用管

> A

## 二、判断题

### 2.1 光凭我们的对象地址,无法确认对象是否存在关联对象

* [ ] 对
* [ ] \[X] 错

### 2.2 int c\[4] = {1,2,3,4}; int *d = c; c\[2] =* (d+2)

* [ ] \[X] 对
* [ ] 错

### 2.3 @interface LGPerson : NSObject{ UIButton \*btn } 其中 btn 是实例变量

* [ ] \[X] 对
* [ ] 错

### 2.4 NSObject 除外 元类的父类 = 父类的元类

* [ ] \[X] 对
* [ ] 错

### 2.5 对象的地址就是内存元素的首地址

* [ ] 对
* [ ] \[X] 错

> 对

### 2.6 类也是对象

* [ ] \[X] 对
* [ ] 错

## 三、简单题

### 3.1 怎么将上层OC代码还原成 C++代码  分值10分

`xcrun 或 clang`

### 3.2 怎么打开汇编查看流程,有什么好处 ?  分值10分

* `debug - DebugWorkflow - Always show disassembly`
* 查看汇编可以从更深层次了解当前函数的汇编层面的执行，为`OBJC`源码分析提供信息，部分源码的执行被LLDB进行了改动，结合会变查看可以避免方向性错误，结合`memory read`可以更清楚的看到寄存器之间是如何让互相配合处理配合的。使用汇编查看流程可以再不确定源码出处和执行流程的情况下，跟踪内部代码，并找到出处。同时，结合符号断点的方式能够更清楚的跟踪源码实现。

### 3.3 x/4gx 和 p/x 以及 p \*$0 代表什么意思  分值10分

* 从首地址开始，1️以8字节的形式打印4段地址
* 打印地址
* 取出`$0`地址中的数据

### 3.4 类方法存在哪里? 为什么要这么设计?  分值10分

* 实例方法保存在类的方法列表中
* 类方法保存在元类的方法列表中
* 这样设计的好处：
  * 底层不用区分类方法和对象方法，本质上都是对象方法。方法调用都可以理解为消息发送，只不过消息的接收者不一样。
  * 这样设计更加的面向对象，类的一切信息都存储在元类中，对象的一切信息都存储在类中。类是元类实例化出的对象，实例对象是类实例化出的对象。存储也更符合面向对象的特点。
  * OC语言早期借鉴了另一种 `SmallTalk`的语言，其中也是这么设计的。

### 3.5 方法慢速查找过程中的二分查找流程,请用伪代码实现 分值10分

### 3.6 ISA\_MASK = 0x00007ffffffffff8ULL 那么这个 ISA\_MASK 的算法意义是什么?  分值10分

ISA包含在`ISA_BITFIELD`中， `& ISA_MASK`是为了去除ISA地址两边的数据（`标志位`、`引用计数`等），拿到正确的ISA地址。

### 3.7 类的结构里面为什么会有 rw 和 ro 以及 rwe ?  分值10分

* class\_ro\_t
  * read only
  * 类名、方法、协议、成员变量等
  * Clean memory
    * 运行时不会改变
* class\_rw\_t
  * read write
  * 使用来读写数据的，在这个数据结构中存储了只有在运行时才会生成的信息。
  * 可读可写
  * Dirty memory
    * 运行时会改变
* class\_rw\_ext\_t
  * read write extension
  * 动态添加的
    * 方法
    * 属性
    * 协议等
  * 这将 class\_rw\_t 的体积减少了进 50%。在有需要的时候将 class\_rw\_ext\_t 插入其中，约 90% 的类用不到这些拓展数据

> Dirty memory 要比 Clean memory 昂贵的多，只要进程在运行，他就一直存在。Clean memory 可以进行移除，以节省空间；如果需要可以再从磁盘中加载。
>
> 之所以将Class的数据分成两部分，是为了尽可能的节省空间

### 3.8 cache 在什么时候开始扩容 , 为什么?  分值10分

* 一般情况
  * 3/4&#x20;
* 真机Arm64
  * 7/8
* 小缓存特殊情况
  * 100%
* 为什么
  * 效率

### 3.9 objc\_msgSend 为什么用汇编写 , objc\_msgSend 是如何递归找到imp?  分值10分

效率高

### 3.10 一个类的类方法没有实现为什么可以调用 NSObject 同名对象方法  分值10分

ISA
