iOS runtime之-方法交換

使用場景

在我們使用系統(tǒng)的方法時,功能有可能不夠用,或者在想在調(diào)用系統(tǒng)的方法時,加一些判斷。當然我可以繼承系統(tǒng)的類,然后重寫該方法。但是有可能項目做得時間比較長,一開始并沒有繼承。這時候再去繼承就會花費一些時間。而且公司來了新人的,并不熟悉公司代碼框架的時候,有可能會忘記繼承。所以這時候我們就可以用運行時給系統(tǒng)方法動態(tài)添加一些代碼。

使用步驟

  • 創(chuàng)建你想交換方法所在類的分類。比如你想在調(diào)用 viewWillAppear時添加一些代碼,那么你就新建一個UIViewController的分類。
  • 包含頭文件#import <objc/runtime.h>
  • 實現(xiàn)+ (void)load{}方法,在這個方法里面動態(tài)交換兩個方法的地址,實現(xiàn)功能。這個方法會在程序加載分類到內(nèi)存的時候就調(diào)用。

主要用到的運行時方法

  • 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:實現(xiàn)這個方法的函數(shù) types:一個定義該函數(shù)返回值類型和參數(shù)類型的字符串 動態(tài)的給一個類添加一個方法
  • IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) 參數(shù)如class_addMethod類似 該函數(shù)可以在運行時動態(tài)替換某個類的函數(shù)實現(xiàn)
  • void method_exchangeImplementations(Method m1, Method m2) 交換兩個方法的地址

例子

在我們開發(fā)中使用可變數(shù)組NSMutableArray 取數(shù)組里面的元素一旦越界就會崩潰。那么有什么辦法,讓線上用戶發(fā)生數(shù)組越界的時候不崩潰呢。這時候就可以用運行時來實現(xiàn)這個功能。

新建NSMutableArray的分類,包含runtime頭文件

// load方法會在類第一次加載到內(nèi)存的時候被調(diào)用  
+ (void)load {
    //方法交換只用執(zhí)行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = NSClassFromString(@"__NSArrayM");
        // 獲取系統(tǒng)數(shù)組的selector
        SEL   systemSelector = @selector(objectAtIndex:);
        // 自己要交換的selector
        SEL   swizzledSelector = @selector(zwb_safeObjectAtIndex:);
        // 兩個方法的Method
        Method originalMethod = class_getInstanceMethod(cls, systemSelector);
        Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);
        //  動態(tài)添加方法
        if (class_addMethod(cls, systemSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
            // 添加成功的話將被交換方法的實現(xiàn)替換到這個并不存在的實現(xiàn)
            class_replaceMethod(cls, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        }else {
            //添加不成功,交換兩個方法的實現(xiàn)
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}
 - (id)zwb_safeObjectAtIndex:(NSUInteger)index {
    if (self.count > index) {
        //一定是自己調(diào)用自己,不會死循環(huán),因為地址已經(jīng)交換,其實調(diào)用的是系統(tǒng)的objectAtIndex
        return [self zwb_safeObjectAtIndex:index];
    }else {
        NSLog(@"數(shù)組越界");
        return nil;
    }
}

當然數(shù)組的其他方法也可以用這種方式防止崩潰,大家可以試試。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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