先看第一個問題:分類的加載順序
舉例UIViewController3個分類分別為
UIViewController+A
UIViewController+B
UIViewController+C
.A
+ (void)load {staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{NSLog(@"----A---");? ? });}
.B
+ (void)load {staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{NSLog(@"----B---");? ? });}
.C
+ (void)load {staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{NSLog(@"----C---");? ? });}
運行結(jié)果
2018-03-2311:06:10.975429+0800ExchangeImp[4802:195579]----C---2018-03-2311:06:10.976176+0800ExchangeImp[4802:195579]----A---2018-03-2311:06:10.976392+0800ExchangeImp[4802:195579]----B---
這個順序是怎么來的的呢褪猛,就不賣關(guān)子了,本文的重點是第二個問題
15217744745721.jpg
其實是這里的順序酌伊,其實壓棧的順序微酬,上面的順序是C,B,A
我們修改下讓以B,A,C輸出
15217745766821.jpg
運行輸出
2018-03-2311:09:23.697753+0800ExchangeImp[4881:201198]----B---2018-03-2311:09:23.698441+0800ExchangeImp[4881:201198]----A---2018-03-2311:09:23.698639+0800ExchangeImp[4881:201198]----C---
第二個問題:多次使用method_exchangeImplementations同一個方法會是怎樣的結(jié)果
method_exchangeImplementations關(guān)于該方法的使用請自行學(xué)習(xí)王污,不是本文的重點
這里我們同時對系統(tǒng)的presentViewController:animated:completion:舉例
代碼結(jié)構(gòu)
.├──ExchangeImp│? ├──AppDelegate.h│? ├──AppDelegate.m│? ├──TestViewController.h│? ├──TestViewController.m│? ├──UIViewController+A.h│? ├──UIViewController+A.m│? ├──UIViewController+B.h│? ├──UIViewController+B.m│? ├──UIViewController+C.h│? ├──UIViewController+C.m│? ├──ViewController.h│? ├──ViewController.m│? └──main.m└──ExchangeImpUITests├──ExchangeImpUITests.m└──Info.plist
A.m
////? UIViewController+A.m//? ExchangeImp////? Created by fangshufeng on 2018/3/23.//? Copyright ? 2018年 fangshufeng. All rights reserved.//#import"UIViewController+A.h"#import<objc/runtime.h>@implementationUIViewController(A)+ (void)load {staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{NSLog(@"---A-被加載了--");? ? ? ? ? Classclass= [selfclass];? ? ? ? ? ? ? ? SEL originalSelector =@selector(presentViewController:animated:completion:);? ? ? ? SEL swizzledSelector =@selector(aAlertPresentViewController:animated:completion:);? ? ? ? ? ? ? ? Method originalMethod = class_getInstanceMethod(class, originalSelector);? ? ? ? Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);? ? ? ? method_exchangeImplementations(originalMethod, swizzledMethod);? ? ? ? ? ? });}- (void)aAlertPresentViewController:(UIViewController*)viewControllerToPresent? ? ? ? ? ? ? ? ? ? ? ? ? animated:(BOOL)flag? ? ? ? ? ? ? ? ? ? ? ? completion:(void(^)(void))completion {NSLog(@"---A-被執(zhí)行了--")? ? ? ? [selfaAlertPresentViewController:viewControllerToPresent? ? ? ? ? ? ? ? ? ? ? ? ? ? animated:flag? ? ? ? ? ? ? ? ? ? ? ? ? completion:completion];}@end
B.m
////? UIViewController+B.m//? ExchangeImp////? Created by fangshufeng on 2018/3/23.//? Copyright ? 2018年 fangshufeng. All rights reserved.//#import"UIViewController+B.h"#import<objc/runtime.h>@implementationUIViewController(B)+ (void)load {staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{NSLog(@"---B-被加載了--");? ? ? ? Classclass= [selfclass];? ? ? ? ? ? ? ? SEL originalSelector =@selector(presentViewController:animated:completion:);? ? ? ? SEL swizzledSelector =@selector(bAlertPresentViewController:animated:completion:);? ? ? ? ? ? ? ? Method originalMethod = class_getInstanceMethod(class, originalSelector);? ? ? ? Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);? ? ? ? method_exchangeImplementations(originalMethod, swizzledMethod);? ? ? ? ? ? });}- (void)bAlertPresentViewController:(UIViewController*)viewControllerToPresent? ? ? ? ? ? ? ? ? ? ? ? ? animated:(BOOL)flag? ? ? ? ? ? ? ? ? ? ? ? completion:(void(^)(void))completion {NSLog(@"---B-被執(zhí)行了--");? ? [selfbAlertPresentViewController:viewControllerToPresent? ? ? ? ? ? ? ? ? ? ? ? ? ? animated:flag? ? ? ? ? ? ? ? ? ? ? ? ? completion:completion];}@end
C.m
////? UIViewController+C.m//? ExchangeImp////? Created by fangshufeng on 2018/3/23.//? Copyright ? 2018年 fangshufeng. All rights reserved.//#import"UIViewController+C.h"#import<objc/runtime.h>@implementationUIViewController(C)+ (void)load {staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{NSLog(@"---C-被加載了--");? ? ? ? Classclass= [selfclass];? ? ? ? ? ? ? ? SEL originalSelector =@selector(presentViewController:animated:completion:);? ? ? ? SEL swizzledSelector =@selector(cAlertPresentViewController:animated:completion:);? ? ? ? ? ? ? ? Method originalMethod = class_getInstanceMethod(class, originalSelector);? ? ? ? Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);? ? ? ? method_exchangeImplementations(originalMethod, swizzledMethod);? ? ? ? ? ? });}- (void)cAlertPresentViewController:(UIViewController*)viewControllerToPresent? ? ? ? ? ? ? ? ? ? ? ? ? animated:(BOOL)flag? ? ? ? ? ? ? ? ? ? ? ? completion:(void(^)(void))completion {NSLog(@"---C-被執(zhí)行了--");? ? [selfcAlertPresentViewController:viewControllerToPresent? ? ? ? ? ? ? ? ? ? ? ? ? ? animated:flag? ? ? ? ? ? ? ? ? ? ? ? ? completion:completion];}@end
ViewController.m
////? ViewController.m//? ExchangeImp////? Created by fangshufeng on 2018/3/23.//? Copyright ? 2018年 fangshufeng. All rights reserved.//#import"ViewController.h"#import"TestViewController.h"@interfaceViewController()@end@implementationViewController- (void)viewDidLoad {? ? [superviewDidLoad];}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event {? ? TestViewController *vc = [[TestViewController alloc] init];? ? [selfpresentViewController:vc animated:YEScompletion:nil];}@end
在build-Phase中的compile source中順序如下
15217831021195.jpg
運行點擊后
2018-03-2311:25:04.816560+0800ExchangeImp[5364:228651]---B-被加載了--2018-03-2311:25:04.817206+0800ExchangeImp[5364:228651]---A-被加載了--2018-03-2311:25:04.817407+0800ExchangeImp[5364:228651]---C-被加載了--2018-03-2311:25:09.314340+0800ExchangeImp[5364:228651]---C-被執(zhí)行了--2018-03-2311:25:09.314502+0800ExchangeImp[5364:228651]---A-被執(zhí)行了--2018-03-2311:25:09.314619+0800ExchangeImp[5364:228651]---B-被執(zhí)行了--
發(fā)現(xiàn)2個現(xiàn)象:
所有的分類方法都被執(zhí)行了见妒;
正好和加載的順序相反
下面具體解釋下這2個現(xiàn)象
在分類A、B隅居、C執(zhí)行之前2個方法是這樣的指向的
15217770799332.jpg
在經(jīng)歷分類B以后,變成下面這樣
15217771048030.jpg
所以在如果沒有A和C的話葛虐,那么在執(zhí)行
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event {? ? TestViewController *vc = [[TestViewController alloc] init];? ? [selfpresentViewController:vc animated:YEScompletion:nil];}
調(diào)用順序為:
presentViewController:animated:completion:?->?NSLog(@"---B-被執(zhí)行了--");?->?bAlertPresentViewController:animated:completion:)
所以輸出順序應(yīng)該是
---B-被執(zhí)行了--
然后彈出vc
回到正題胎源,那么在執(zhí)行分類A之前的樣子,A方法和presentViewController:animated:completion:指向就是下圖
15217773012806.jpg
在執(zhí)行分類A以后屿脐,指向如下
15217773565704.jpg
所以如果沒有分類C的話這時候的輸出應(yīng)該為
---A-被執(zhí)行了--
---B-被執(zhí)行了--
繼續(xù)分析涕蚤,在分類c執(zhí)行之前宪卿,各個指向為下圖
15217774989252.jpg
執(zhí)行以后如下
15217775721780.jpg
則執(zhí)行順序就很清楚了,到這里也就解釋了為何一開始是的輸出
2018-03-2311:25:04.816560+0800ExchangeImp[5364:228651]---B-被加載了--2018-03-2311:25:04.817206+0800ExchangeImp[5364:228651]---A-被加載了--2018-03-2311:25:04.817407+0800ExchangeImp[5364:228651]---C-被加載了--2018-03-2311:25:09.314340+0800ExchangeImp[5364:228651]---C-被執(zhí)行了--2018-03-2311:25:09.314502+0800ExchangeImp[5364:228651]---A-被執(zhí)行了--2018-03-2311:25:09.314619+0800ExchangeImp[5364:228651]---B-被執(zhí)行了--
接下來通過logo打印證實上面的觀點
改造下之前的代碼以B.m為例
////? UIViewController+B.m//? ExchangeImp////? Created by fangshufeng on 2018/3/23.//? Copyright ? 2018年 fangshufeng. All rights reserved.//#import"UIViewController+B.h"#import<objc/runtime.h>@implementationUIViewController(B)+ (void)load {staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{NSLog(@"---B-被加載了--");? ? ? ? Classclass= [selfclass];? ? ? ? ? ? ? ? SEL originalSelector =@selector(presentViewController:animated:completion:);? ? ? ? SEL swizzledSelector =@selector(bAlertPresentViewController:animated:completion:);? ? ? ? ? ? ? ? Method originalMethod = class_getInstanceMethod(class, originalSelector);? ? ? ? Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);NSLog(@"B-begin---%p-----%p",method_getImplementation(originalMethod),method_getImplementation(swizzledMethod));? ? ? ? method_exchangeImplementations(originalMethod, swizzledMethod);NSLog(@"B-after---%p-----%p",method_getImplementation(originalMethod),method_getImplementation(swizzledMethod));? ? });}- (void)bAlertPresentViewController:(UIViewController*)viewControllerToPresent? ? ? ? ? ? ? ? ? ? ? ? ? animated:(BOOL)flag? ? ? ? ? ? ? ? ? ? ? ? completion:(void(^)(void))completion {NSLog(@"---B-被執(zhí)行了--");? ? [selfbAlertPresentViewController:viewControllerToPresent? ? ? ? ? ? ? ? ? ? ? ? ? ? animated:flag? ? ? ? ? ? ? ? ? ? ? ? ? completion:completion];}@end
執(zhí)行以后
ExchangeImp[6709:319693]---B-被加載了--ExchangeImp[6709:319693]B-begin---0x10cedabc8-----0x10b6241d0ExchangeImp[6709:319693]B-after---0x10b6241d0-----0x10cedabc8ExchangeImp[6709:319693]---A-被加載了--ExchangeImp[6709:319693]A-begin---0x10b6241d0-----0x10b624450ExchangeImp[6709:319693]A-after---0x10b624450-----0x10b6241d0ExchangeImp[6709:319693]---C-被加載了--ExchangeImp[6709:319693]C-begin---0x10b624450-----0x10b6246d0ExchangeImp[6709:319693]C-after---0x10b6246d0-----0x10b624450
主要看下originalMethod的地址
A的開始bengin的開始也即是originalMethod指向為0x10b6241d0万栅,正是在BB-after中交換后的0x10b6241d0
可以看到每次交換的開始都是上次交換的結(jié)果
結(jié)論
多次對某個方法進行method_exchangeImplementations所有交換的都會執(zhí)行到佑钾,執(zhí)行順序可以自己在build-phase中修改
(完)