Method Swizzlingのメソッドレコード

3206 ワード

           Method Swizzling   ,    Method Swizzling     

一、方法
hook UIViewControllerを例に
#import 

@implementation UIViewController (Tracking)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];

        SEL originalSelector = @selector(viewWillAppear:);
        SEL swizzledSelector = @selector(xxx_viewWillAppear:);

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

        // When swizzling a class method, use the following:
        // Class class = object_getClass((id)self);
        // ...
        // Method originalMethod = class_getClassMethod(class, originalSelector);
        // Method swizzledMethod = class_getClassMethod(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)xxx_viewWillAppear:(BOOL)animated {
    [self xxx_viewWillAppear:animated];
    NSLog(@"viewWillAppear: %@", self);
}

@end

上記は一般的な方法であり、hookするMethod(swizzledMethodIMP)を追加することを試み、追加に成功した場合、swizzledSelectorの実装をoriginalMethodに置き換えることで、2つの方法で実装された交換が完了する.追加に失敗した場合(すなわち、このclassに対応するMethodが既に存在する)、2つのMethodの実装を直接交換する.UIViewControllerのようなviewWillAppear:メソッドが特定されているクラスでは、もちろんmethod_exchangeImplementationsをサボって直接使用して完成することができますが、上記の方法ではより厳密です.
二、+load vs.+initialize
Method Swizzling     +load     
+initializeは、クラスのメソッドまたはそのインスタンスが最初に呼び出される前に、+initializeメソッドが呼び出されるだけです.つまり、呼び出されない可能性があります.+loadメソッドは、main関数の実行前に呼び出され、各クラス、分類されたloadメソッドが呼び出されます.呼び出されると、すべてのframeworkが実行時にロードされます(ただし、まだロードされていないクラスもあります).1つのクラスのloadメソッドで他のクラスを呼び出すメソッドは、呼び出されたクラスがload未満の場合、呼び出されたクラスのloadメソッドをトリガーしません.
三、dispatch_once Method Swizzilingが一度だけ行われることを可能な限り保証するために、コードはdispatch_onceに含まれるべきである.
四、第三者
GitHubにはAspectのようなサードパーティがあり、Method Swizzlingメソッドがカプセル化されており、選択コードが元のメソッドの前後で実行されるか、元のメソッドを直接置き換えるなどの他の機能が提供されています.Hookオブジェクト、クラスなど.いくつかのサードパーティ統計も、統計の機能を実現するために同様の方法を使用していることが明らかである.
五、参考
  • Method Swizzling--Matttt Thompson、Method Swizzlingの使用について詳しく説明しました.
  • 本当にloadの方法を知っていますか?--Draveness,load法の原理
  • を解析した.
  • loadメソッドとinitializeメソッドの実行順序およびクラスとオブジェクトの関係は、各クラスloadメソッドの呼び出し順序がcompile sourceのファイル順序に関係する
  • である.