iOS進階—Runtime基礎
阿新 • • 發佈:2018-12-04
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類。這就是類物件傳送改變。