1. 程式人生 > >Runtime 防止閃退

Runtime 防止閃退

      正常情況下App的閃退大部分是由陣列越界;字典插入空值;字串擷取越界;定時器nstimer;kvo;野指標,殭屍物件等導致的閃退。一般在測試時正常如果後臺返回不正常資料,前端沒做防護的情況下很容易閃退。通過Runtime 可以在資料錯誤交換方法或者return避免閃退。但是runtime不可亂用,特別是多人開發時,如果不注意交換同一個方法就會出現問題。這個一般在上線開啟,除錯關閉。只能避免閃退不能避免bug。還是需要在程式碼中多做判斷,防止越界,nil插入等情況! demo

  以前也研究過一些關於runtime防護的相關問題都不夠全面。最近在看部落格時看到幾篇很不錯的部落格和一些總結很不錯的demo.

Runtime 在專案中的常見使用:

1 字典轉模型;

2  動態新增交換攔截方法;防止閃退,換膚,統一設定字型顏色或者全域性某個方法攔截

3 熱更新;用到的依然是runtime 裡面的轉連結  forwardingTargetForSelector

4 獲取屬性列表;

5 歸檔解檔;

6 動態新增屬性 ;分類不可新增屬性 通過runtime可以實現

7 實現萬能跳轉; 這個在收到訊息時跳到具體頁面通過類名生成相應物件

Method class_getClassMethod(Class cls, SEL name) cls:需要交換的類方法的所屬類 class SEL:該類方法獲取一個類的類方法的地址

Method class_getInstanceMethod(Class cls, SEL name) cls:需要交換的類例項方法的所屬類 class SEL:該類的例項方法獲取一個類的例項方法地址

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types) cls:被新增方法的類名 name:方法名 imp:實現這個方法的函式 types:一個定義該函式返回值型別和引數型別的字串動態的給一個類新增一個方法

IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) 引數如class_addMethod類似該函式可以在執行時動態替換某個類的函式實現

void method_exchangeImplementations(Method m1, Method m2)交換兩個方法的地址

 

runtime 在防護方面最核心的是通過method_exchangeImplementations交換IMP從而交換方法。就是當你掉用的方法出現錯誤時掉用自己的方法或者return從而防止Crash 同時上傳閃退的記錄便於修復。

一班都會在分類中新增方法例如NSarray:

1 新建分類

2  #import <objc/runtime.h> 引進框架

3 load方法裡寫交換方法 ,未什麼放在load裡可以搜(main函式前發生了什麼)至於為什麼要用dispatch_once 方法交換應該被保證,在程式中只會執行一次

+ (void)load

{

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

 

        Class clsI = NSClassFromString(@"__NSArrayI");

 

        Method method1 = class_getInstanceMethod(clsI, @selector(objectAtIndexedSubscript:));

        Method method2 = class_getInstanceMethod(clsI, @selector(yye_objectAtIndexedSubscript:));

        method_exchangeImplementations(method1, method2);

 

        Method method3 = class_getInstanceMethod(clsI, @selector(objectAtIndex:));

        Method method4 = class_getInstanceMethod(clsI, @selector(yye_objectAtIndex:));

        method_exchangeImplementations(method3, method4);

 

        Class clsSingleI = NSClassFromString(@"__NSSingleObjectArrayI");

        Method method5 = class_getInstanceMethod(clsSingleI, @selector(objectAtIndex:));

        Method method6 = class_getInstanceMethod(clsSingleI, @selector(yyeSingle_objectAtIndex:));

        method_exchangeImplementations(method5, method6);

    });

}

- (id)yye_objectAtIndexedSubscript:(NSUInteger)index{

    if(index>=self.count) return self.lastObject;

 

    return [self yye_objectAtIndexedSubscript:index];

}

- (id)yye_objectAtIndex:(NSUInteger)index{

    if(index>=self.count) return self.lastObject;

 

    return [self yye_objectAtIndex:index];

}

- (id)yyeSingle_objectAtIndex:(NSUInteger)index{

    if(index>=self.count){

        return self.lastObject;

    }

 

    return [self yyeSingle_objectAtIndex:index];

}

1:  + (void)load與+ (void)initialize的區別:+ (void)load:當類載入進記憶體的時候呼叫,而且不管有沒有子類,都只會呼叫一次,在main函式之前呼叫,用途:1:可以新建類在該類中實現一些配置資訊 2:runtime交換方法的時候,因為只需要交換一次方法,所有可以在該方法中實現交換方法的程式碼,用於只實現一次的程式碼 

2:+ (void)initialize:當類被初始化的時候呼叫,可能會被呼叫多次,若是沒有子類,則只會呼叫一次,若是有子類的話,該方法會被呼叫多次,若是子類的繼承關係,先會呼叫父類的+ (void)initialize方法,然後再去呼叫子類的+ (void)initialize方法(若是繼承關係,呼叫某個方法的時候,先會去父類中查詢,若是父類中沒有方法的實現就去子類中查詢) 用途:1:在設定導航欄的全域性背景的時候,只需要設定一次,可以重寫該方法設定,最好是在該方法判斷子類,若是自己,則實現設定全域性導航欄的方法,若不是自己則跳過實現。2:在建立資料庫程式碼的時候,可以在該方法中去建立,保證只初始化一次資料庫例項,也可以用dispatch或是懶載入的方法中初始化資料庫例項,也能保證只初始化一次資料庫例項。其中也可以在+ (void)initialize方法中用dispatch也能保證即使有子類也只會初始化一次

   2:交換方法:1:獲取某個類的方法:class_getClassMethod:第一個引數:獲取哪個類的方法 第二個引數:SEL:獲取哪個方法

  Method imageNamedMethod = class_getClassMethod(self, @selector(imageNamed:));

 // 互動方法:runtime

  method_exchangeImplementations(imageNamedMethod, xmg_imageNamedMethod);

 也就是外部呼叫xmg_imageNamed就相當於呼叫了imageNamed,呼叫imageNamed就相當於呼叫了xmg_imageNamed

 3:在分類中,最好不要重寫系統方法,一旦重寫,把系統方法實現給幹掉,因為分類不是繼承父類,而是繼承NSObject,super沒有改類的方法,所以就直接覆蓋掉了父類的行為

關於部落格網上很多都大同小異 建立分類 交換方法 部落格

關於demo這個還是總結的比較好:demo  這個demo 裡面比較全但是需要經過關閉提示 ;除錯時關閉上線開啟。WKCrashManagerDemo這個demo 使用時注意幾個warning的地方最好自己整理裡整理。上面文章總結不夠全面想到再繼續補充!

相關連結:

runtime詳解:http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/

預防閃退demo原連結: https://www.jianshu.com/p/d2a0f8174c30

黑魔法教你讓iOS APP防住Crash  https://www.jianshu.com/p/02157577d4e7

runtime 萬能跳轉 http://www.cocoachina.com/ios/20150824/13104.html

runtime 之訊息轉發: https://www.jianshu.com/p/5127ce0628be

runtime 幾種常見使用:http://www.cocoachina.com/cms/wap.php?action=article&id=24384