同一個方法使用method_exchangeImplementations多次

先看第一個問題:分類的加載順序

舉例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中修改

項目地址

(完)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市烦粒,隨后出現(xiàn)的幾起案子休溶,更是在濱河造成了極大的恐慌,老刑警劉巖扰她,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兽掰,死亡現(xiàn)場離奇詭異,居然都是意外死亡义黎,警方通過查閱死者的電腦和手機禾进,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門豁跑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來廉涕,“玉大人,你說我怎么就攤上這事艇拍『桑” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵卸夕,是天一觀的道長层释。 經(jīng)常有香客問我,道長快集,這世上最難降的妖魔是什么贡羔? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮个初,結(jié)果婚禮上乖寒,老公的妹妹穿的比我還像新娘。我一直安慰自己院溺,他們只是感情好楣嘁,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著珍逸,像睡著了一般逐虚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谆膳,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天叭爱,我揣著相機與錄音,去河邊找鬼漱病。 笑死买雾,一個胖子當(dāng)著我的面吹牛馒胆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凝果,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼祝迂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了器净?” 一聲冷哼從身側(cè)響起型雳,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎山害,沒想到半個月后纠俭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡浪慌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年冤荆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片权纤。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡钓简,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出汹想,到底是詐尸還是另有隱情外邓,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布古掏,位于F島的核電站损话,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏槽唾。R本人自食惡果不足惜丧枪,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望庞萍。 院中可真熱鬧拧烦,春花似錦、人聲如沸挂绰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽葵蒂。三九已至交播,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間践付,已是汗流浹背秦士。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留永高,地道東北人隧土。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓提针,卻偏偏與公主長得像,于是被迫代替她去往敵國和親曹傀。 傳聞我的和親對象是個殘疾皇子辐脖,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容