運(yùn)行時(shí)runtime深度解析(二)—— Method Swizzling在頁(yè)面統(tǒng)計(jì)上的應(yīng)用

版本記錄

版本號(hào) 時(shí)間
V1.0 2017.07.27

前言

OC是運(yùn)行時(shí)的語(yǔ)言贵试,底層就是運(yùn)行時(shí),可以說(shuō)runtime是OC的底層体捏,很多事情也都可以用運(yùn)行時(shí)解決呆馁,下面就講述一下運(yùn)行時(shí)runtime的知識(shí)以及它的妙用。感興趣的可以看上面幾篇鹊漠。
1. 運(yùn)行時(shí)runtime深度解析(一)—— API

Method Swizzling

Method Swizzing是發(fā)生在運(yùn)行時(shí)的主到,主要用于在運(yùn)行時(shí)將兩個(gè)Method進(jìn)行交換,我們可以將Method Swizzling代碼寫(xiě)到任何地方躯概,但是只有在這段Method Swilzzling代碼執(zhí)行完畢之后互換才起作用登钥。而且Method Swizzling也是iOS中AOP(面相切面編程)的一種實(shí)現(xiàn)方式,我們可以利用蘋(píng)果這一特性來(lái)實(shí)現(xiàn)AOP編程娶靡。

在OC語(yǔ)言的runtime特性中牧牢,調(diào)用一個(gè)對(duì)象的方法就是給這個(gè)對(duì)象發(fā)送消息。是通過(guò)查找接收消息對(duì)象的方法列表,從方法列表中查找對(duì)應(yīng)的SEL塔鳍,這個(gè)SEL對(duì)應(yīng)著一個(gè)IMP(一個(gè)IMP可以對(duì)應(yīng)多個(gè)SEL)伯铣,通過(guò)這個(gè)IMP找到對(duì)應(yīng)的方法調(diào)用。在每個(gè)類(lèi)中都有一個(gè)Dispatch Table轮纫,這個(gè)Dispatch Table本質(zhì)是將類(lèi)中的SEL和IMP(可以理解為函數(shù)指針)進(jìn)行對(duì)應(yīng)腔寡。而我們的Method Swizzling就是對(duì)這個(gè)table進(jìn)行了操作,讓SEL對(duì)應(yīng)另一個(gè)IMP掌唾。

下面看其原理圖放前。

原理圖

1. 方法互換在頁(yè)面統(tǒng)計(jì)上的應(yīng)用需求

很多公司都有頁(yè)面統(tǒng)計(jì)這個(gè)需求,這里我們也做一下統(tǒng)計(jì)糯彬,主要有兩種思路:

  • 在每一個(gè)控制器中viewDidLoad方法中統(tǒng)計(jì)用戶(hù)進(jìn)入控制器的次數(shù)凭语,并上報(bào)至服務(wù)器。但是這有個(gè)缺點(diǎn)就是每一個(gè)控制器都要加很是繁瑣撩扒。
  • 還有一種辦法就是寫(xiě)一個(gè)UIViewController的分類(lèi)Category似扔,然后在Category中的+(void)load方法中添加Method Swizzling方法,我們用來(lái)替換的方法也寫(xiě)在這個(gè)Category中却舀。由于load類(lèi)方法是程序運(yùn)行時(shí)這個(gè)類(lèi)被加載到內(nèi)存中就調(diào)用的一個(gè)方法,執(zhí)行比較早挽拔,并且不需要我們手動(dòng)調(diào)用辆脸。而且這個(gè)方法具有唯一性,也就是只會(huì)被調(diào)用一次螃诅,不用擔(dān)心資源搶奪的問(wèn)題啡氢。

這里我們采用的是第二種方法,正好也驗(yàn)證下Method Swizzling方法的使用术裸。

2. 方法互換在頁(yè)面統(tǒng)計(jì)上的應(yīng)用實(shí)現(xiàn)

下面我們就直接看代碼吧倘是。

1. JJRuntimeVC.h
#import <UIKit/UIKit.h>

@interface JJRuntimeVC : UIViewController

@end

2. JJRuntimeVC.m
#import "JJRuntimeVC.h"
#import "UIViewController+JJSwizzlingCategory.h"

@interface JJRuntimeVC ()

@end

@implementation JJRuntimeVC

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor greenColor];
}

@end

3. UIViewController+JJSwizzlingCategory.h
#import <UIKit/UIKit.h>

@interface UIViewController (JJSwizzlingCategory)

@end

4. UIViewController+JJSwizzlingCategory.m
#import "UIViewController+JJSwizzlingCategory.h"
#import <objc/runtime.h>

@implementation UIViewController (JJSwizzlingCategory)

#pragma mark - Override Base Function

+ (void)load
{
    [super load];
    
    //通過(guò)class_getInstanceMethod()函數(shù)從當(dāng)前對(duì)象中的method list獲取method結(jié)構(gòu)體,如果是類(lèi)方法就使用class_getClassMethod()函數(shù)獲取袭艺。
    Method replacedMathod = class_getInstanceMethod([self class], @selector(viewDidLoad));
    Method toReplaceMethod = class_getInstanceMethod([self class], @selector(swizzlingMethodViewDidLoad));
    
//    我們?cè)谶@里使用class_addMethod()函數(shù)對(duì)Method Swizzling做了一層驗(yàn)證搀崭,如果self沒(méi)有實(shí)現(xiàn)被交換的方法,會(huì)導(dǎo)致失敗猾编。
//    而且self沒(méi)有交換的方法實(shí)現(xiàn)瘤睹,但是父類(lèi)有這個(gè)方法,這樣就會(huì)調(diào)用父類(lèi)的方法答倡,結(jié)果就不是我們想要的結(jié)果了轰传。
//    所以我們?cè)谶@里通過(guò)class_addMethod()的驗(yàn)證,如果self實(shí)現(xiàn)了這個(gè)方法瘪撇,class_addMethod()函數(shù)將會(huì)返回NO获茬,我們就可以對(duì)其進(jìn)行交換了港庄。
    if (!class_addMethod([self class], @selector(viewDidLoad), method_getImplementation(toReplaceMethod), method_getTypeEncoding(toReplaceMethod))) {
        method_exchangeImplementations(replacedMathod, toReplaceMethod);
    }
}

#pragma mark - Action && Notification

- (void)swizzlingMethodViewDidLoad
{
    NSString *str = [NSString stringWithFormat:@"%@",self.class];
    // 我們?cè)谶@里加一個(gè)判斷,將系統(tǒng)的UIViewController的對(duì)象剔除掉
    if (![str containsString:@"UI"]) {
        NSLog(@"統(tǒng)計(jì)打點(diǎn):%@",self.class);
    }

    [self swizzlingMethodViewDidLoad];
}

@end

運(yùn)行代碼會(huì)發(fā)現(xiàn)恕曲,先走+ (void)load實(shí)現(xiàn)方法的互換鹏氧,再走控制器JJRuntimeVC中的viewDidLoad方法,但是由于在+ (void)load中對(duì)方法的實(shí)現(xiàn)做了互換佩谣,所以走的是方法- (void)swizzlingMethodViewDidLoad度帮,在這個(gè)方法內(nèi)部接著調(diào)用[self swizzlingMethodViewDidLoad];,同樣由于方法實(shí)現(xiàn)的互換稿存,其實(shí)調(diào)用的是方法- (void)viewDidLoad,所以最后又走正常的走了這個(gè)方法瞳秽,同時(shí)實(shí)現(xiàn)了對(duì)加載控制器的統(tǒng)計(jì)瓣履,下面看結(jié)果輸出。

2017-07-27 19:07:27.892845+0800 JJOC[5763:1911605] 統(tǒng)計(jì)打點(diǎn):JJRuntimeVC

這樣就利用運(yùn)行時(shí)實(shí)現(xiàn)了頁(yè)面統(tǒng)計(jì)练俐。


參考文獻(xiàn)

1. Method Swizzling
2. Objective-C Runtime 運(yùn)行時(shí)之四:Method Swizzling
3. iOS黑魔法-Method Swizzling

后記

未完袖迎,待續(xù)~~~~

風(fēng)光無(wú)限好
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市腺晾,隨后出現(xiàn)的幾起案子燕锥,更是在濱河造成了極大的恐慌,老刑警劉巖悯蝉,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件归形,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鼻由,警方通過(guò)查閱死者的電腦和手機(jī)暇榴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蕉世,“玉大人蔼紧,你說(shuō)我怎么就攤上這事『萸幔” “怎么了奸例?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)向楼。 經(jīng)常有香客問(wèn)我查吊,道長(zhǎng),這世上最難降的妖魔是什么蜜自? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任菩貌,我火速辦了婚禮,結(jié)果婚禮上重荠,老公的妹妹穿的比我還像新娘箭阶。我一直安慰自己虚茶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布仇参。 她就那樣靜靜地躺著嘹叫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诈乒。 梳的紋絲不亂的頭發(fā)上罩扇,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音怕磨,去河邊找鬼喂饥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛肠鲫,可吹牛的內(nèi)容都是我干的员帮。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼导饲,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼捞高!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起渣锦,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤硝岗,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后袋毙,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體型檀,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年听盖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贱除。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡媳溺,死狀恐怖月幌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情悬蔽,我是刑警寧澤扯躺,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站蝎困,受9級(jí)特大地震影響录语,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜禾乘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一澎埠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧始藕,春花似錦蒲稳、人聲如沸氮趋。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)剩胁。三九已至,卻和暖如春祥国,著一層夾襖步出監(jiān)牢的瞬間昵观,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工舌稀, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啊犬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓壁查,卻偏偏與公主長(zhǎng)得像椒惨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子潮罪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

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