Search code examples
objective-cmethod-swizzling

Method swizzling doesn't work in Objective-C


I want to test method swizzling in Objective-C:

  1. Add a method goodName in AViewController

    #import "AViewController.h"
    #import "UIViewController+Tracking.h"
    @interface AViewController ()
    
    @end
    
    @implementation AViewController
     - (void)viewDidLoad {
        [super viewDidLoad];
        [self goodName];
    }
     - (void) goodName {
        NSLog(@"I am a good Name");
    }
    @end
    
  2. Add a category for swizzling goodName method.

    #import "UIViewController+Tracking.h"
    #import <objc/runtime.h>
    #import "AViewController.h"
    @implementation UIViewController (Tracking)
    
    + (void) load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            Class class = [self class];
            SEL originalSelector = @selector(goodName);
            SEL swizzledSelector = @selector(xxx_xxx_goodName);
    
            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);
            }
        });
    }
    
    - (void)xxx_xxx_goodName {
        NSLog(@"i am xxx goodName");
        [self xxx_xxx_goodName];
    }
    
    @end
    
  3. If everything works well, the goodName was called will output i am xxx goodName, but it's output I am a good Name.

Any part wrong?


Solution

  • You're trying to swizzle methods in AViewController but you put the code in +(void)load for base UIViewController. Those are two separate class objects so you need to do it in +(void)load for AViewController.