docs: SSL/TLS

This commit is contained in:
LiuBinPeng
2022-05-24 13:00:23 +08:00
parent 7241220c8e
commit 4f11b95363
90 changed files with 4054 additions and 451 deletions

View File

@@ -2,6 +2,58 @@
> 做很多需求或者是技术细节验证的时候会用到 Runtime 技术,用了挺久的了,本文就写一些场景和源码分析相关的文章。
## 动态语言
Runtime 是实现 OC 语言动态的 API。
静态语言:在编译阶段确定了变量数据类型、函数地址等,无法动态修改。
动态语言:只有在运行的时候才可以决定变量属于什么类型、方法真正的地址,
对象 `objc_object` 存了isa、成员变量的值
类 objc_class: superclass、成员变量、实例变量
```objectivec
@interface Person : NSObject
{
NSString *_name;
}
@property (nonatomic, strong) NSString *hobby;
@end
malloc_size((__bridge const void *)(p)) // 24 isa占8字节 + _name 指针占8字节 + hobby 指针占8字节 = 24
class_getInstanceSize(p.class) // 32 ,系统内存对齐
```
为什么内存对齐以空间换时间。系统以16字节对齐。
x /6gx p.class
类对象有且仅有1个。
p.class
class_getClass("Person")
[Person class]
p/x (class_data_bits_t *)地址
## class_rw_t、class_ro_t 区别?
class_ro_t 在编译时期生成的class_rw_t 是在运行时期生成的。
拷贝带来的问题?当开发者通过 runtime第一次 动态修改类的信息的时候Apple 会生成 rwe。搜索 class_rw_ext_t
## 有类对象、为什么设计元类对象
复用消息机制。比如 `[Person new]`
元类对象: isa、元类方法、
`objc_msgSend` 设计初衷就是为了消息发送很快。假如没有元类,则类方法也存储在类对象的方法信息中,则可能需要加额外的字段来标记某个方法是类方法还是对象方法。遍历或者寻找会比较慢。所以引入元类(单一职责),设计元类的目的就是为了提高 `objc_msgSend` 的效率。
## isa 本质
在 arm64 架构之前isa 就是一个普通的指针,存储着 Class或Meta-Class 对象的内存地址。
@@ -89,7 +141,7 @@ isa 在 arm64 之后必须通过 `ISA_MASK` 去查询 class类对象、元类
`0x0000000ffffffff8ULL` 用程序员模式打开计算器
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/objc-isa-mask.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/objc-isa-mask.png)
其中,结构体中的数据存放大体是下面的结构:
@@ -291,7 +343,7 @@ struct class_ro_t {
具体关系整理如下图
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-class.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-class.png)
说明:
@@ -299,7 +351,7 @@ struct class_ro_t {
为什么不是二维数组因为Array 中的子 Array长度不一致且不能补空
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-class-rw-t.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-class-rw-t.png)
```c
static void remethodizeClass(Class cls)
@@ -384,7 +436,7 @@ struct class_ro_t {
- `class_ro_t` 里面的 baseMethodList、baseProtocols、ivars、baseProperties 是一维数组,是只读的,包含了类的(原始信息)初始内容
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-class-ro-t.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-class-ro-t.png)
## Method_t
@@ -422,7 +474,7 @@ typedef struct objc_selector *SEL;
iOS 中提供了一个叫做 `@encode` 的指令,可以将具体的类型表示成字符串编码
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-method-encoding.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-method-encoding.png)
```objectivec
- (int)calcuate:(int)age heigith:(float)height;
@@ -774,7 +826,7 @@ NSLog(@"%s %p", bucket._key, bucket._imp);
// personSay 0xbec8
```
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-method-find.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-method-find.png)
原理就是根据类对象结构体找到 cache 结构体cache 结构体内部的 `_buckets` 是一个方法散列表,查看源代码,根据散列表的哈希寻找策略 `(key & mask)` 找到哈希索引,然后找到方法对象 bucket其中寻找方法索引的 key 就是 方法 selector。
@@ -1359,7 +1411,7 @@ for 循环不断查找,找当前类的父类,直到当前类为 nil。
上面的流程是整个 `objc_msgSend` 的消息发送阶段的整个流程。可以用下图表示
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-objc_msgSend-messageSend.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-objc_msgSend-messageSend.png)
### 动态方法解析阶段
@@ -1494,7 +1546,7 @@ SEL_resolveClassMethod, sel);`
完整流程如下
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-objc_msgSend-ResolveMethod.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-objc_msgSend-ResolveMethod.png)
上 Demo
@@ -1634,7 +1686,7 @@ void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
为什么是 `__forwarding__` 方法。我们可以根据 Xcode 崩溃窥探一二
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-forwardingFailed.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-forwardingFailed.png)
```c
int __forwarding__(void *frameStackPointer, int isStret) {
@@ -1678,7 +1730,7 @@ int __forwarding__(void *frameStackPointer, int isStret) {
完整流程如下
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-forwarding.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-forwarding.png)
上 Demo
@@ -1899,7 +1951,7 @@ objc_msgSendSuper(arg, sel_registerName("class"))
我们对 iOS 项目`[super viewDidLoad]` 下符号断点,发现`objc_msgSendSuper2`
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-super.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-super.png)
查看 objc4 源代码发现是一段汇编实现。
@@ -2133,7 +2185,7 @@ void test () {
方法内的变量存储在栈上,堆向上增长,栈向下增长。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-isa-demo.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-isa-demo.png)
3.**实例对象的本质就是一个结构体存储所有成员变量isa 是一个特殊成员变量,其他的成员变量,这里就是 _name`sayHi` 方法内部的 self 就是 obj找成员变量的本质就是找内存地址的过程此时就是偏移8个字节**
@@ -2182,7 +2234,7 @@ objc_msgSendSuper(arg, sel_registerName("viewDidLoad"));
所以此时的“前一个局部变量” 也就是结构体 `objc_super` 类型的 arg。arg 是一个结构体,结构体第一个成员变量就是 self所以“前一个局部变量” 也就是 selfViewController
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-super-isa-demo.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-super-isa-demo.png)
## 应用场景
@@ -2216,7 +2268,7 @@ Person *p = [Person new];
object_setClass(p, [Student class]);
```
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-changeisa-demo.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-changeisa-demo.png)
3.动态创建类
@@ -2243,7 +2295,7 @@ void createClass (void) {
}
```
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/runtime-dynamicCreateClass-demo.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/assets/runtime-dynamicCreateClass-demo.png)
runtime 中 copy、create 等出来的内存,不使用的时候需要手动释放`objc_disposeClassPair(newClass>)`