Runtime替換實現方法

Method Swizzling

//
//  UIViewController+Tracking.m
//  tesssss
//
//  Created by iOS on 23/11/17.
//  Copyright ? 2017年 iOS. All rights reserved.
//

#import "UIViewController+Tracking.h"
#import <objc/runtime.h>

@implementation UIViewController (Tracking)

// 放在load方法中,當類被加載之后就執行以下方法。
+ (void)load {
    // 防止手動調用 class 方法,保證替換方法只執行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];
        SEL originalSelector = @selector(viewWillAppear:);
        SEL swizzledSelector = @selector(ICE_viewWillAppear:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        /*
         class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,
         const char * _Nullable types)

         *  Class cls     cls 參數表示需要添加新方法的類。
         *  SEL name      name 參數表示 selector 的方法名稱,可以根據喜好自己進行命名。
         *  IMP imp       imp 即 implementation ,表示由編譯器生成的、指向實現方法的指針。也就是說,這個指針指向的方法就是我們要添加的方法。
         *  const char *types   最后一個參數 *types 表示我們要添加的方法的返回值和參數。
         
         如果發現方法已經存在,會失敗返回,也可以用來做檢查是否已經添加過方法了,我們這里是為了避免源方法沒有實現的情況;
         如果方法沒有存在,我們則先嘗試添加被替換的方法的實現
         */
        BOOL didAddMethod = class_addMethod(
                                            class,
                                            originalSelector,
                                            method_getImplementation(swizzledMethod),
                                            method_getTypeEncoding(swizzledMethod)
                                            );
        
        /*
         判斷class_addMethod是否已經添加成功了
         YES 則說明被替換方法不存在.也就是被替換的方法沒有被實現,我們需要先把這個方法實現,然后再執行我們想要的效果,用我們自定義的方法去替換被替換的方法. 這里使用到的是class_replaceMethod這個方法. class_replaceMethod本身會嘗試調用class_addMethod和method_setImplementation,所以直接調用class_replaceMethod就可以了)

         NO  則說明被替換方法已經存在.直接將兩個方法的實現交換即
         */
        if (didAddMethod) {
            class_replaceMethod(
                                class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod)
                                );
        }
        else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

- (void)ICE_viewWillAppear:(BOOL)animated {
    [self ICE_viewWillAppear:animated];
    NSLog(@"ICEviewWillAppear:%@",self);
}
@end

          //如果替換的是類方法
          Class classB = Object_getClass ((id) self);

          SEL originalSelector = @selector (想要替換的類方法);
          SEL swizzledSelector = @selector (替換的新方法名) ;

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

推薦閱讀更多精彩內容