RunTime 基础
一个程序的执行过程,大概就是代码->编译链接->执行
C语言
#import <Foundation/Foundation.h>
void run() {
NSLog(@"%s", __func__);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
run();
}
return 0;
}
执行结果:
2018-11-16 11:41:34.373347+0800 Runtime001[2263:82588] run
Program ended with exit code: 0
OC 属于消息发送机制,包含SEL 和IMP,如果把OC理解为一本书,SEL (编号)代表书目录的文章标题,IMP(指针)代表文章对应页码,方法实现本身则是正文
Runtime进行同类方法交换
#import <Foundation/Foundation.h>
#import "TZPerson.h"
#import "TZDog.h"
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
TZPerson* p = [TZPerson new];
Method m1 = class_getInstanceMethod([p class], @selector(walk));
Method m2 = class_getInstanceMethod([p class], @selector(run));
IMP imp = method_getImplementation(m2);
method_setImplementation(m1, imp);
[p walk];
}
return 0;
}
执行结果:我们调用的walk
,执行的是run
方法
2018-11-16 11:49:45.681647+0800 Runtime001[2356:87721] -[TZPerson run]
Program ended with exit code: 0
Method
本身是typedef struct objc_method *Method;
结构体。我们可以查看Runtime源码(参考GitHub)objc-runtime-master
上面的代码与下面的代码等价
struct method_t {
SEL name;
const char *types;
IMP imp;
// struct SortBySELAddress :
// public std::binary_function<const method_t&,
// const method_t&, bool>
// {
// bool operator() (const method_t& lhs,
// const method_t& rhs)
// { return lhs.name < rhs.name; }
// };
};
int main(int argc, const char * argv[]) {
@autoreleasepool {
TZPerson* p = [TZPerson new];
Method m1 = class_getInstanceMethod([p class], @selector(walk));
struct method_t * m2 = class_getInstanceMethod([p class], @selector(run));
// IMP imp = method_getImplementation(m2);
method_setImplementation(m1, m2->imp);
[p walk];
}
return 0;
}
OC在调用类方法时,也可以对C语言的函数进行调用,比如下面的例子
#import <Foundation/Foundation.h>
#import "TZPerson.h"
#import <objc/runtime.h>
void run() {
NSLog(@"%s", __func__);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
TZPerson* p = [TZPerson new];
Method m1 = class_getInstanceMethod([p class], @selector(walk));
method_setImplementation(m1, (IMP)run);
[p walk];
}
return 0;
}
OC进行调用类交换,如下
#import <Foundation/Foundation.h>
#import "TZPerson.h"
#import "TZDog.h"
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
TZPerson* p = [TZPerson new];
TZDog* d = [TZDog new];
object_setClass(p, [d class]);
[p walk];
}
return 0;
}
执行结果如下:
2018-11-16 14:39:19.802920+0800 Runtime001[3662:134196] -[TZDog walk]
Program ended with exit code: 0
本来调用的Person,但是替换成了Dog类。这就是类对象发送改变。