Search code examples
iosobjective-cuiviewcontrollermodalviewcontrollermethod-swizzling

Advanced method swizzling in Objective-C, iOS 9?


The question is simple. I need the same as usually - how to replace the original method with my one but @selector(presentViewController:animated:completion:) in iOS9? It works in iOS9 simulator only, not real device.

Yes this code is called but then you get EXC_BAD_ACCESS.

To test it I created a test app from "Master-Detail template" added a button and added the following code:

UIViewController *vc = [[UIViewController alloc] init];
[self.navigationController presentViewController:vc animated:YES completion:nil];

UPDATED

@implementation UINavigationController (Extension)

- (void)swizzledPresentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
{
    [ self swizzledPresentViewController:viewControllerToPresent animated:flag completion:completion ];
}

#pragma mark -

+ (void)swizzle:(Class)class oldSelector:(SEL)old newSelector:(SEL)new
{
    Method oldMethod = class_getInstanceMethod(class, old);
    Method newMethod = class_getInstanceMethod(class, new);


    if(class_addMethod(class, old, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
    {
        class_replaceMethod(class, new, method_getImplementation(oldMethod), method_getTypeEncoding(oldMethod));
    }
    else
    {
        method_exchangeImplementations(oldMethod, newMethod);
    }
}

+ (void)load
{
    [self swizzle:UINavigationController.class oldSelector:@selector(presentViewController:animated:completion:) newSelector:@selector(swizzledPresentViewController:animated:completion:)];
}

@end

And almost the same code is written on NSHipster website

UPDATED

WARNING! This bug is reproduced on very random devices (in my case it is iphone5 + ios9.0, but other users have newer devices and with iOS9.1).


Solution

  • The problem is swizzling breaks checking nil values. Solutions for this case:

    1)check if block is nil then replace it with empty non-nil block

    2)use ready libraries. I tried: https://github.com/rabovik/RSSwizzle