運行時runtime深度解析(二)—— Method Swizzling在頁面統計上的應用

版本記錄

版本號 時間
V1.0 2017.07.27

前言

OC是運行時的語言,底層就是運行時,可以說runtime是OC的底層,很多事情也都可以用運行時解決,下面就講述一下運行時runtime的知識以及它的妙用。感興趣的可以看上面幾篇。
1. 運行時runtime深度解析(一)—— API

Method Swizzling

Method Swizzing是發生在運行時的,主要用于在運行時將兩個Method進行交換,我們可以將Method Swizzling代碼寫到任何地方,但是只有在這段Method Swilzzling代碼執行完畢之后互換才起作用。而且Method Swizzling也是iOS中AOP(面相切面編程)的一種實現方式,我們可以利用蘋果這一特性來實現AOP編程。

在OC語言的runtime特性中,調用一個對象的方法就是給這個對象發送消息。是通過查找接收消息對象的方法列表,從方法列表中查找對應的SEL,這個SEL對應著一個IMP(一個IMP可以對應多個SEL),通過這個IMP找到對應的方法調用。在每個類中都有一個Dispatch Table,這個Dispatch Table本質是將類中的SEL和IMP(可以理解為函數指針)進行對應。而我們的Method Swizzling就是對這個table進行了操作,讓SEL對應另一個IMP。

下面看其原理圖。

原理圖

1. 方法互換在頁面統計上的應用需求

很多公司都有頁面統計這個需求,這里我們也做一下統計,主要有兩種思路:

  • 在每一個控制器中viewDidLoad方法中統計用戶進入控制器的次數,并上報至服務器。但是這有個缺點就是每一個控制器都要加很是繁瑣。
  • 還有一種辦法就是寫一個UIViewController的分類Category,然后在Category中的+(void)load方法中添加Method Swizzling方法,我們用來替換的方法也寫在這個Category中。由于load類方法是程序運行時這個類被加載到內存中就調用的一個方法,執行比較早,并且不需要我們手動調用。而且這個方法具有唯一性,也就是只會被調用一次,不用擔心資源搶奪的問題。

這里我們采用的是第二種方法,正好也驗證下Method Swizzling方法的使用。

2. 方法互換在頁面統計上的應用實現

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

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];
    
    //通過class_getInstanceMethod()函數從當前對象中的method list獲取method結構體,如果是類方法就使用class_getClassMethod()函數獲取。
    Method replacedMathod = class_getInstanceMethod([self class], @selector(viewDidLoad));
    Method toReplaceMethod = class_getInstanceMethod([self class], @selector(swizzlingMethodViewDidLoad));
    
//    我們在這里使用class_addMethod()函數對Method Swizzling做了一層驗證,如果self沒有實現被交換的方法,會導致失敗。
//    而且self沒有交換的方法實現,但是父類有這個方法,這樣就會調用父類的方法,結果就不是我們想要的結果了。
//    所以我們在這里通過class_addMethod()的驗證,如果self實現了這個方法,class_addMethod()函數將會返回NO,我們就可以對其進行交換了。
    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];
    // 我們在這里加一個判斷,將系統的UIViewController的對象剔除掉
    if (![str containsString:@"UI"]) {
        NSLog(@"統計打點:%@",self.class);
    }

    [self swizzlingMethodViewDidLoad];
}

@end

運行代碼會發現,先走+ (void)load實現方法的互換,再走控制器JJRuntimeVC中的viewDidLoad方法,但是由于在+ (void)load中對方法的實現做了互換,所以走的是方法- (void)swizzlingMethodViewDidLoad,在這個方法內部接著調用[self swizzlingMethodViewDidLoad];,同樣由于方法實現的互換,其實調用的是方法- (void)viewDidLoad,所以最后又走正常的走了這個方法,同時實現了對加載控制器的統計,下面看結果輸出。

2017-07-27 19:07:27.892845+0800 JJOC[5763:1911605] 統計打點:JJRuntimeVC

這樣就利用運行時實現了頁面統計。


參考文獻

1. Method Swizzling
2. Objective-C Runtime 運行時之四:Method Swizzling
3. iOS黑魔法-Method Swizzling

后記

未完,待續~~~~

風光無限好
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容