一、初识runtime
OC是一种运行时语言,就是编译期做的事情推迟到运行期在决定,这就意味着OC不仅需要一个编译器,而且还需要一个运行期环境,这个运行期环境就是Runtime。
高级编程语言想要成为可执行文件需要先编译为汇编语言再汇编为机器语言,机器语言也是计算机能够识别的唯一语言,OC(面向对象)需要runtime转为纯C(面向过程 )语言再进行编译和汇编的操作;这就需要将面向对象的类转变为面向过程的结构体。
- id
#if !OBJC_TYPES_DEFINED
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
#endif
通过上面可以知道,我们创建一个对象或实例其实就是一个struct objc_object结构体,而我们常用的id也就是这个结构体的指针
- nil
#ifndef nil
# if __has_feature(cxx_nullptr)
# define nil nullptr
# else
# define nil __DARWIN_NULL
# endif
#endif
等同于C语言中的NULL; 在Objective-C中表示一个指向对象的空指针。(该对象没有存储任何内存地址)
- Nil
#ifndef Nil
# if __has_feature(cxx_nullptr)
# define Nil nullptr
# else
# define Nil __DARWIN_NULL
# endif
#endif
Nil表示一个指向 类 的空指针。(该类没有存储任何内存地址)
- SEL 方法选择器
typedef struct objc_selector *SEL;
编译器会根据每个方法的方法名为那个方法生成唯一的SEL,这些SEL组成了一个Set集合,这个Set简单的说就是一个经过了优化过的hash表。因此,如果我们想到这个方法集合中查找某个方法时,只需要去找到这个方法对应的SEL就行了,SEL实际上就是根据方法名hash化了的一个字符串,而对于字符串的比较仅仅需要比较他们的地址就可以了
通过下面三种方法可以获取SEL:
1、sel_registerName函数
2、Objective-C编译器提供的@selector()
3、NSSelectorFromString()方法
- IMP,方法实现的指针
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
#endif
一个函数指针,保存了方法的地址
- Method
typedef struct objc_method *Method;
struct objc_method {
SEL method_name; //方法名称
char *method_types; //参数和返回类型的描述字串
IMP method_imp; //方法的具体的实现的指针
};
我们可以看到该结构体中包含一个SEL和IMP,实际上相当于在SEL和IMP之间作了一个映射。有了SEL,我们便可以找到对应的IMP,从而调用方法的实现代码
- Class
类在OC中是objc_class的结构体指针
typedef struct objc_class *Class;
在objc/runtime.h中objc_class结构体的定义如下:
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY; // 指向元类的指针
#if !__OBJC2__
Class _Nullable super_class // 父类
const char * _Nonnull name // 类名
long version // 类的版本信息,默认为0
long info // 类信息,供运行期使用的一些位标识
long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
struct objc_ivar_list * _Nullable ivars // 该类的成员变量链表
struct objc_method_list * _Nullable * _Nullable methodLists // 方法定义的链表
struct objc_cache * _Nonnull cache // 方法缓存
struct objc_protocol_list * _Nullable protocols // 协议链表
#endif
} OBJC2_UNAVAILABLE;
元数据:类对象就是一个结构体struct objc_class,这个结构体存放的数据就是元数据。