3

I have a UIViewController with this code:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    NSLog(@"CLASIC");
}

And then I have a framework with a UIViewController category that does swizzling in this manner:

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        SEL viewWillAppearSelector = @selector(viewDidAppear:);
        SEL viewWillAppearLoggerSelector = @selector(logged_viewDidAppear:);
        Method originalMethod = class_getInstanceMethod(self, viewWillAppearSelector);
        Method extendedMethod = class_getInstanceMethod(self, viewWillAppearLoggerSelector);
        method_exchangeImplementations(originalMethod, extendedMethod);

    });
}

- (void)logged_viewDidAppear:(BOOL)animated
{
    [self logged_viewDidAppear:animated];

    NSLog(@"SWIZZLED");
}

The output is SWIZZLED and then CLASIC.

Now my question is: if in my viewcontroller I comment the [super viewDidAppear:animated]; then the swizzled method does not get called anymore; why is that? I understood most of the aspects but it seems this one somehow slipped.

- (void)viewDidAppear:(BOOL)animated
{
    // we comment this and this will trigger the swizzled method not being called anymore
    //[super viewDidAppear:animated];
    NSLog(@"CLASIC");
}

// ========================

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        SEL viewWillAppearSelector = @selector(viewDidAppear:);
        SEL viewWillAppearLoggerSelector = @selector(logged_viewDidAppear:);
        Method originalMethod = class_getInstanceMethod(self, viewWillAppearSelector);
        Method extendedMethod = class_getInstanceMethod(self, viewWillAppearLoggerSelector);
        method_exchangeImplementations(originalMethod, extendedMethod);

    });
}

- (void)logged_viewDidAppear:(BOOL)animated
{
    [self logged_viewDidAppear:animated];

    NSLog(@"SWIZZLED");
}
Catalin
  • 1,821
  • 4
  • 26
  • 32
  • You commented out the method call and the method is not called anymore - what else did you expect exactly? – mag_zbc Nov 07 '18 at 11:52
  • @mag_zbc I commented the super call, what does the swizzled method that replaces the current one have to do with the super? – Catalin Nov 07 '18 at 12:28

1 Answers1

4

Method swizzling is used for overriding original methods with the custom one at runtime. So you can exchange almost any method, (including the private apple implemented ones) with the custom one you wrote.

So imagine there is class named Parent with a method named A and you exchange it with B somewhere before it been called like inside load method. From now on every sub class off 'Parent' will use B except the original 'A' method. But what if you override A in a child class? As Inheritance definition, objects will call their own methods and if they haven't implement it, they use their suprclass's method. So what if you want the parent implementation? Thats where super comes in.

Conclusion

  • If you override a method, the super class (or the custom exchanged method in superclass) method will not getting called
  • If you want the parent implementation, you have to use super keyword to access it

And in this questions case:

  • Overriding a method in sub class without calling super means you just override swizzled method and it will not getting called.

Hope it helps

Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
  • I think I got it... I was in VC1 which inherited UIViewController, but I only replaced the viewDidAppear in all UIViewController, but in VC1 it overrides the method making my swizzling unfunctional, unless I call super, correct? – Catalin Nov 07 '18 at 12:31
  • Yes the method you swizzled is in `UIViewController` (parent) ;) – Mojtaba Hosseini Nov 07 '18 at 12:33
  • Many thanks... it makes sense now :) but is there any way to be sure that in subclasses my swizzle method will get call even if the super is not called? :) – Catalin Nov 07 '18 at 12:40
  • 1
    @Catalin It might be possible to swizzle all classes that are subclasses of UIViewController in the output of `objc_getClassList`. But there are a few edge cases for doing it that way. – Mats Nov 07 '18 at 14:41
  • Thank @Mats I almost forgot that ‍♂️ – Mojtaba Hosseini Nov 07 '18 at 14:42