iOS中若是對Runtime有必定了解的話,必定據說過或者用過這個函數
void method_exchangeImplementations(Method m1, Method m2),它一般就是所說的method swizzling,算是ObjC的」黑魔法」了,做用就是在程序運行期間動態的給兩個方法互換實現;ios好比:
程序中有許多個ViewController,我想在對項目改動最小的狀況下,在當每一個Controller執行完ViewDidLoad之後就在控制檯把本身的名字打印出來,方便去作調試或者瞭解項目結構函數其實咱們的目的就是重寫ViewDidLoad的方法,並在他的方法最後加上幾句Log,因此咱們須要給UIViewController創建一個category,由於咱們知道,若是在Catagory中重寫一個方法,就會覆蓋它的原有方法實現,可是,這樣作之後就沒有辦法調用系統原有的方法,由於在一個方法裏調用本身的方法會是一個死循環。因此咱們的解決辦法就是,另外寫一個方法來和viewDidLoad「交換」,這樣外部調用viewDidLoad就會調到新建的這個方法中,一樣,咱們調用新建的方法就會調用到系統的viewDidLoad中了spa
第一種方案:.net
#import "UIViewController+viewDidLoad.h" #import <objc/runtime.h> @implementation UIViewController (viewDidLoad) + (void)load { //保證交換方法只執行一次 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //獲取這個類的viewDidLoad方法,它的類型是一個objc_moethod結構體的指針 Method viewDidLoad = class_getInstanceMethod(self, @selector(viewDidLoad)); //獲取自定義的方法 Method viewDidLoaded = class_getInstanceMethod(self, @selector(viewDidUnload)); //互換兩個方法實現 method_exchangeImplementations(viewDidLoad, viewDidLoaded); }); } //新建一個方法與viewDidload交換 - (void)viewDidLoaded { [self viewDidLoaded]; NSLog(@"%@ did load",self); }
第二種方案:指針
IMP 它是一個指向方法實現的指針,每個方法都一個對應的IMP指針。咱們能夠直接調用方法的IMP指針,來避免方法調用死循環的問題調試
//修改的方法有返回值就用IMP,無返回值就用VIMP typedef id (*_IMP) (id,SEL,...); typedef void (*_VIMP) (id,SEL,...); #import "UIViewController+viewDidLoad.h" #import <objc/runtime.h> @implementation UIViewController (viewDidLoad) + (void)load { //保證交換方法只執行一次 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //獲取原始方法 Method viewDidLoad = class_getInstanceMethod(self, @selector(viewDidLoad)); //獲取方法實現 _VIMP viewDidLoad_IMP = (_VIMP)method_getImplementation(viewDidLoad); //從新設置方法實現 method_setImplementation(viewDidLoad,imp_implementationWithBlock(^(id target,SEL action){ viewDidLoad_IMP(target,@selector(viewDidLoad)); //自定義代碼 NSLog(@"%@ did load",target); })); }); }
修改的方法有返回值就用IMP,沒有返回值就用VIMP。重寫的方法有返回值,不要忘記在最後作returncode
實際上直接調用一個方法的IMP指針的效率是高於調用方法自己的,若是有一個合適的時機獲取到方法的IMP的話,能夠試着調用IMP而不用調用方法。get