1

There is a slight variation between these 2 ways of swizzling. I just want clarification if there is something fundamentally different or wrong between them

Assuming we are swizzling viewDidLoad on UIView

First way (using class_addMethod):

@implementation UIView (SwizzleFirstWay)

+ (void)load  {
    SEL originalSelector = @selector(viewDidLoad);
    SEL swizzledSelector = @selector(swizzled_viewDidLoad);
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
    class_addMethod(self,
                    originalSelector,
                    class_getMethodImplementation(self, originalSelector),
                    method_getTypeEncoding(originalMethod));

    // Adding the method
    class_addMethod(self,
                    swizzledSelector,
                    class_getMethodImplementation(self, swizzledSelector),
                    method_getTypeEncoding(swizzledMethod));
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

+ (void)swizzled_viewDidLoad {
    // ... the swizzled implementation
    // ...
    // ...
    [self swizzled_viewDidLoad]; // calling back to the original implementation
}

@end

Second way (without using class_addMethod):

+ (void)load  {
    SEL originalSelector = @selector(viewDidLoad);
    SEL swizzledSelector = @selector(swizzled_viewDidLoad);
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
    // NOT USING class_addMethod
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

+ (void)swizzled_viewDidLoad {
    // ... the swizzled implementation
    // ...
    // ...
    [self swizzled_viewDidLoad]; // calling back to the original implementation
}

@end
Borys Verebskyi
  • 4,160
  • 6
  • 28
  • 42
Avba
  • 14,822
  • 20
  • 92
  • 192
  • Is your code working? you are calling class_getInstanceMethod for selector swizzled_viewDidLoad, but that function is Class Method, not Instance Method. – Sahil Doshi Aug 11 '17 at 13:19

1 Answers1

0

Very good question, actually. If you use method_exchangeImplementations without calling class_addMethod first, you can accidentally swizzle your superclass implementation. The reason for that is class_getInstanceMethod searches superclasses for inherited implementation in a case when a method is not implemented in the class itself. And it is, obviously, not something you want to achieve.

A quick example. Using following code

@interface UIWebView (SwizzlingTest)

- (void)swizzled_removeFromSuperview {
    [self swizzled_removeFromSuperview];
}

+ (void)load {
    SEL originalSelector = @selector(removeFromSuperview);
    SEL swizzledSelector = @selector(swizzled_removeFromSuperview);
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

@end

Results in

-[UICheckeredPatternView swizzled_removeFromSuperview]: unrecognized selector sent to instance 0x101b24250

because removeFromSuperview is inherited from UIView, but not implemented in UIWebView.

Borys Verebskyi
  • 4,160
  • 6
  • 28
  • 42