Rumtime都能干什么
- 动态改变方法的执行体
- Method Swizzling
- NSSelectorFromString,NSClassFromString…
- 动态添加属性(主要是类别)
- 动态遍历属性和方法,动态为类添加方法
学习Rumtime,基本的概念很重要,计划Rumtime这个系列计划几篇文章
- 讲讲一些基本概念(文本),例如SEL,Class,id,IMP等等
- 详解iOS中消息的传递机制,以及消息转发机制,内存分配,类对象,元类对象
- Method Swizzling
- 其他常见实际应用
什么是Runtime?
Objective-C语言把能在运行期做的事情就推迟到运行期在决定。这就意味着,Objective-C不仅需要一个编译器,而且需要一个运行期环境。这个运行期环境就是Runtime。
最直接的例子就是方法的调用
[receiver message]
这样的一个OC方法会被编译成:
objc_msgSend(receiver, selector)
这里,先记着receiver就是接受信息的对象,selector是执行消息的函数体名称,是个C的字符串。是像其他语言一样,直接编译成一个指向函数体的指针。
那么,在运行的时候,如何通过objc_megSend(receiver, selector)找到实际的函数体呢?
SEL/objc_selector
objc_selector是一个数据结构,可以理解为一个C String
SEL
源码的定义如下:
typedef struct objc_selector *SEL;
也就是说,SEL是一个指向C String的指针。
id/objc_object
- id 是指向一个类的实例对象
底层代码的定义
typedef struct objc_object *id;
其中 objc_object的底层定义
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
可以看到objc_object中只保存了一个Class类型的isa指针。这里看不懂不要怕,先记着,对象中就是保存了一个指向Objective C中对应类的指针。
Class/objc_class
- Class是指向Objective-C类对象(objc_class)的一个指针
底层代码
typedef struct objc_class *Class;
objc_class
底层定义
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
可以看到,这就是类对象结构体的定义,细心的同学可能发现了类对象里仍然有一个指针Class isa,先记着,这个isa指向的是类元对象。这个我会在下一篇文章里详细阐述
IMP
- IMP是指向实际执行函数体的指针
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id (*IMP)(id, SEL, ...);
#endif
可以看到,这个函数体前两个参数是 id(消息接受者,也就是对象),以及SEL(方法的名字)
method/objc_method
- method是指向Objective-C中的方法的指针
typedef struct objc_method *Method;
其中
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
_cmd
SEL 类型的一个变量,Objective C的函数的前两个隐藏参数为self 和 _cmd
Ivar
ivar - Objective-C中的实例变量
typedef struct objc_ivar *Ivar;
可以看到变量的内存模型
struct objc_ivar {
char *ivar_name OBJC2_UNAVAILABLE;
char *ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;