ios 底层原理 Runtime的探索(一)

492 阅读3分钟

这篇文章是我自己学习runtime时候的笔记,水平有限有需要补充或者指正的地方,希望提出来,大家一起学习

一.Runtime的含义

  • Runtime 是一套由C,C++及汇编语言组成的提供给Objective-C(简写OC)_运行时_使用的API

我们知道OC程序运行的过程分为编译->链接->运行等几个步骤,OC语言尽可能的把一些操作推迟到运行时,动态的处理一些问题。

  • Runtime 在三种层面上与 OC 系统进行交互:
  1. 通过 Objective-C 源代码间接使用Runtime
  2. 通过 Foundation 框架的 NSObject 类定义的方法
  3. 通过对 Runtime API的直接调用
  • Runtime的常用应用
  1. 消息转发
  2. 方法交换( Method swizzling)
  3. 动态的添加类对象的成员变量和方法,分类中添加属性
  4. 获取某个类的所有成员变量和成员方法
  5. 实现字典模型的自动转换
  6. 防止程序crash 等

二.对象与方法的本质

  • 查看对象和方法的本质之前,我们需要准备
  1. 你可以在这里(opensource.apple.com/source/objc…

  2. Clang编译器的使用

  • 对象的本质探索

创建工程 ->创建MRPerson类,打开终端,cd到工程地址根目录下,输入命令:clang -rewrite-objc main.m -o test.cpp,在文件夹中我们可以看到test.cpp的生产文件

如图:

打开text.cpp文件-> 拉到最底部main函数部分可以看到

搜索test.app文件中的MRPerson类,如下图

对象MRPerson是objc_object的结构体,所以我们可以得到这样的结论:OC对象的本质是结构体

  • 方法的本质探索

在test.app文件中,除了objc_getClass外还有一行objc_msgSend

如上图我们可以得出这样的一个结论:方法的本质是发送消息

  • 类方法与实例方法

直接调用Runtim API 的objc_msgSend()方法,会报“Implicit declaration of function 'objc_msgSend' is invalid in C99”错误.所以应该在main函数文件中导入**#include <objc/message.h>**头文件,才能使用Runtime API的方式查看类方法和实例方法的具体实现

小知识点:#include,#import,@class的区别:

1.#import是object-c导入头文件的关键字,#include是C/c++导入头文件的关键字

2.使用#import导入头文件会自动只导入一次,不会重复导入

3.@class是告诉编译器某个类的声明,当执行时,才会去查看类的实现文件,可以解决头文件的相互包含

4.#import <>用来包含系统的头文件,#import ""是包含用户的头文件。

调取objc_msgSend(id _Nullable self, SEL _Nonnull op, ...) 方法出现

错误,需要在xcode->Build Settings  设置为NO:

类方法与实例方法具体实现(父类,元类,基类)

上图可看出:

  • 当发送消息给实例对象时,消息是在寻找这个对象的类的方法列表(实例方法)

  • 当发送消息给类对象时,消息是在寻找这个类的元类的方法列表(类方法)

对象在类中以实例的方式存储

类在元类中也是以实例的方式存储