我的女神——簡潔實用的iOS代碼調試架構

來源:互聯網
上載者:User

標籤:

我的女神——簡潔實用的iOS代碼調試架構一、引言

        這篇部落格的起源是接手了公司的一個已經完成的項目,來做代碼最佳化,項目工程很大,並且引入了很多公司內部的SDK,要搞清楚公司內部的這套架構,的確不是件容易的事,並且由於這個項目是多人開發的,在調試階段會列印出巨量的調試資訊,使得瀏覽有用資訊變的十分困難,更加恐怖的是,很多資訊是SDK中的調試列印,將這些都進行登出是非常費勁甚至不可能的事,於是便有了這樣一些需求:首先,我需要清楚瞭解各個controller之間的跳轉關係,需要快速的弄清每個stroyBoard中各個controller的來龍去脈,其次,我想在不改變其他人的調試代碼的情況下,屏蔽冗餘的log資訊,讓我的調試資料更加清晰明了。於是我想到了如下的解決方案,同樣,如果你有更好的方案或者你知道的優秀的解決辦法,請告知我,十分感謝。

二、追蹤程式的跳轉路徑

        這是一個很容易解決的問題,我們都知道,一個controller,如果要展現出來,一定會走生命週期中的viewWillAppear這個方法,我們只需要在這個方法中做些手腳就可以了,實現有兩種思路,一種是採用工廠的設計模式,建立工廠類Controller,在其viewWillAppear中加入我們的調試代碼,但這對於我的項目並不實用,首先我不確定所有controller都會繼承於一個父類,其次,在我沒有找到源頭時,這些類已經在公司的framework中了,我根本沒辦法操作源碼。而第二種方案就是runtime,對的,運行時的OC,沒有不可能。關於runtime的詳細說明,在http://my.oschina.net/u/2340880/blog/489072中有介紹。思路是我們可以寫一個方法,替換掉系統的viewWillAppear,在其中加入我們的調試代碼,這個方法就是Method Swizzing,代碼設計如下:

//建立一個conreoller的類別#import "UIViewController+YHBaseTest.h"#import <objc/runtime.h>@implementation UIViewController (YHBaseTest)+ (void)load {    //只執行一次的線程    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        Class class = [self class];        // When swizzling a class method, use the following:        // Class class = object_getClass((id)self);        //建立兩個選取器 分別指向 系統的和我們要替換的函數        SEL originalSelector = @selector(viewWillAppear:);        SEL swizzledSelector = @selector(YHBaseViewWillAppear:);        //擷取方法執行個體        Method originalMethod = class_getInstanceMethod(class, originalSelector);        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);        //現將方法加入        BOOL didAddMethod =        class_addMethod(class,                        originalSelector,                        method_getImplementation(swizzledMethod),                        method_getTypeEncoding(swizzledMethod));        //進行方法替換        if (didAddMethod) {            class_replaceMethod(class,                                swizzledSelector,                                method_getImplementation(originalMethod),                                method_getTypeEncoding(originalMethod));        } else {            method_exchangeImplementations(originalMethod, swizzledMethod);        }    });}#pragma mark - Method Swizzling- (void)YHBaseViewWillAppear:(BOOL)animated {//這裡是是我加的一個控制調試鎖 後面會介紹    [self YHBaseViewWillAppear:animated];    YHBaseProcessLog(@"YHBaseTest:ViewWillAppear: %@", self);    }
三、屏蔽冗餘的log資訊1、系統的NSLog是個什麼玩意

        要戰勝我們的敵人,首先應該瞭解我們的敵人,我們想要屏蔽NSLog的列印,先需要清楚NSLog到底是個什麼玩意。

        首先,NSLog的定義如下:

FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);FOUNDATION_EXPORT void NSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0);

這裡面有兩個函數,一個是使用多參的格式化字串進行NSLog的列印,一個是通過參數指標進行列印。從這裡我們可以看出,系統的NSLog是一個C風格的函數,所以,我們有思路了,我們可以通過定義一個NSLog宏來替換掉項目中所有的NSLog,如下:

//...是省略參數的宏的寫法,後面的__VA_ARGS__是系統定義好的一個宏,來聲明不定參數#define NSLog(...) YHBaseTestLog(__VA_ARGS__)
2、實現我們自己的NSLog

        通過上面的方法,在沒有動源碼的情況下,我們已經可以替換掉程式中所有的列印,可能你會疑問,程式中怎麼會允許我們有兩個NSLog呢,其實這沒什麼神奇的,要知道宏是一種先行編譯的指令,所有這些操作是在代碼編譯之前完成的,實際上程式中已經將NSLog簡單替換成了我們的函數調用,程式中只有一個NSLog,這就是宏的強大之處,狸貓換太子,不錯吧。

        下面我們來實現我們的這個函數,如下:

//不要忘了在.h檔案中聲明void YHBaseTestLog(NSString *str,...){//參數列    va_list list;    va_start(list, str);    //這個地方是一個鎖,後面會介紹    if (![YHBaseTestLock sharedTheSingletion]->_customLock) {    //進行列印           NSLogv(str, list);    }    va_end(list);}

這個函數中其實並沒有做什麼,加了一個鎖的判斷,僅此而已,核心的控制,就交給我們的鎖吧:

//.h檔案@interface YHBaseTestLock : NSObject<YHSingletonProcotol>{    @public    BOOL _customLock;    BOOL _precessLock;}+(void)customLock;+(void)customUnLock;+(void)processLogLock;+(void)processLogUnLock;//.m//單例方法+(instancetype)sharedTheSingletion{    static YHBaseTestLock * sharedModel = nil;    static dispatch_once_t predicate;    dispatch_once(&predicate, ^{        sharedModel = [[YHBaseTestLock alloc] init];    });    return sharedModel;}- (instancetype)init{    self = [super init];    if (self) {    //初始化 預設使用者的列印都開起        _customLock=NO;        //預設 我們加的controller的列印屏蔽        _precessLock=YES;    }    return self;}//響應的設定+(void)customLock{    [YHBaseTestLock sharedTheSingletion]->_customLock=YES;}+(void)customUnLock{      [YHBaseTestLock sharedTheSingletion]->_customLock=NO;}+(void)processLogLock{     [YHBaseTestLock sharedTheSingletion]->_precessLock=YES;}+(void)processLogUnLock{    [YHBaseTestLock sharedTheSingletion]->_precessLock=NO;}
四、看看我們的傑作吧

        做完上面的工作後,我們在appdelegate中如如下的簡單配置:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    // Override point for customization after application launch.    //將使用者列印加鎖    [YHBaseTestLock customLock];    //將流程列印解鎖    [YHBaseTestLock processLogUnLock];    return YES;}

我們做如下測試:

@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.   NSLog(@"111111111111111111111111111111111111111111111111111111111111111");    [YHBaseTestLock customUnLock];    NSLog(@"這個是有用的資訊:%@==%d",@"看我哦",__LINE__);    [YHBaseTestLock customLock];    NSLog(@"32123213123214412312312");}

我在viewController中的有用資訊前後,列印了一些幹擾資訊,並且可以看到,這個NSLog的格式和系統的完全相容,在列印有用資訊前後解鎖和加鎖,結果如下:

可以看到,我們將沒用的列印都屏蔽了,並且列印了程式的跳轉流程。最重要的是,我們對源碼一個字元都沒有修改,同時不會影響與衝突其他人的開發。


這篇部落格開頭,我稱之為我的女神,真心實感,這個方法幫了我很大的忙,在我瞭解項目的結構架構前,每次調試列印都在控制區滾出一片片的資訊著實讓我頭暈腦脹,現在一清涼,精神也清爽不少,^_^。



我的女神——簡潔實用的iOS代碼調試架構

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.