Hook原理介绍
1.Objective-C消息传递(Messaging)
对于C/C++这类静态语言,调用一个方法其实就是跳到内存中的某一点并开始执行一段代码。没有任何动态的特性,因为这在编译时就决定好了。
而在 Objective-C 中,[object foo] 语法并不会立即执行 foo 这个方法的代码。它是在运行时给 object 发送一条叫 foo 的消息。这个消息,也许会由 object 来处理,也许会被转发给另一个对象,或者不予理睬假装没收到这个消息。多条不同的消息也可以对应同一个方法实现。这些都是在程序运行的时候动态决定的。
事实上,在编译时你写的 Objective-C 函数调用的语法都会被翻译成一个 C 的函数调用 objc_msgSend() 。比如,下面两行代码就是等价的:
[people TailName:@"Test" Age:18];
objc_msgSend(people, @selector(TailName:Age:), "Test", 18);
在 Objective-C 中,类、对象和方法都是一个C的结构体,从 objc/objc.h 和 objc/runtime.h 头文件中,我们可以找到他们的定义:
typedef struct objc_class *Class;
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
//Class 是一个 objc_class 结构类型的指针, id是一个 objc_object 结构类型的指针.
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class
const char *name
long version
long info
long instance_size
struct objc_ivar_list *ivars
struct objc_method_list **methodLists
struct objc_cache *cache
struct objc_protocol_list *protocols
#endif
} OBJC2_UNAVAILABLE;
isa
是一个 objective-c Class 类型的指针. 实例对象有个isa的属性,指向Class, 而Class里也有个isa的属性, 指向meteClass. 这里就有个点, 在Objective-C中任何的类定义都是对象.super_class
指向该类的父类, 如果该类已经是最顶层的根类(如 NSObject 或 NSProxy),那么 super_class 就为 NULL.
![](./img/objective-c.png)
name
类的名字version
类的版本信息,默认为0info
供运行期使用的一些位标识。instance_size
该类的实例变量大小ivars
成员变量的链表
struct objc_ivar_list {
int ivar_count
/* variable length structure */
struct objc_ivar ivar_list[1]
}
- methodLists
方法定义的链表struct objc_method_list { struct objc_method_list *obsolete; int method_count; struct objc_method method_list[1]; }; struct objc_method { SEL method_name; char *method_types; IMP method_imp;
};
- objc_cache
指向最近使用的方法.用于方法调用的优化
struct objc_cache {
unsigned int mask /* total = mask + 1 */;
unsigned int occupied;
Method buckets[1];
};
- protocols
协议的链表
struct objc_protocol_list {
struct objc_protocol_list *next;
long count;
Protocol *list[1];
};
objc_method_list 本质是一个有 objc_method 元素的可变长度的数组。一个 objc_method 结构体中:
- 函数名,也就是SEL
- 表示函数原型的字符串 (见 Type Encoding)
- 函数的实现IMP
#### 2. Method Swizzling示例
以上面可知方法的名字(SEL)跟方法的实现(IMP,指向 C 函数的指针)一一对应。Swizzle 一个方法其实就是在程序运行时对 objc_method_list 里做点改动,让这个方法的名字(SEL)对应到另个IMP。
Method Swizzling(方法调配技术),仅针对Objective-C方法有效。Method Swizzling 利用 Runtime 特性把一个方法的实现与另一个方法的实现进行替换。
//涉及到的主要方法
class_addMethod
class_replaceMethod
method_exchangeImplementations