UINavigationController+XWTransition.m 3.26 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
//
//  UINavigationController+XWTransition.m
//  XWTADemo
//
//  Created by wazrx on 16/6/7.
//  Copyright © 2016年 wazrx. All rights reserved.
//

#import "UINavigationController+XWTransition.h"
#import "UIViewController+XWTransition.h"
#import "XWTransitionAnimator.h"
#import <objc/runtime.h>
#import <objc/message.h>

@implementation UINavigationController (XWTransition)

+ (void)load{
    method_exchangeImplementations(class_getInstanceMethod([self class], @selector(pushViewController:animated:)), class_getInstanceMethod([self class], @selector(_xw_pushViewController:animated:)));
}

- (void)xw_pushViewController:(UIViewController *)viewController withAnimator:(XWTransitionAnimator *)animator {
    if (!viewController) return;
    XWInteractiveTransition *toInteractive = objc_getAssociatedObject(self.topViewController, &kXWToInteractiveKey);
    if (toInteractive) {
        [animator setValue:toInteractive forKey:@"toInteractive"];
    }
    if (animator) {
        objc_setAssociatedObject(viewController, &kXWAnimatorKey, animator, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    [self pushViewController:viewController animated:YES];
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self _xw_swizzeViewControlelrDealloc];
    });
}

- (void)_xw_swizzeViewControlelrDealloc{
    Class swizzleClass = [UIViewController class];
    @synchronized(swizzleClass) {
        SEL deallocSelector = sel_registerName("dealloc");
        __block void (*originalDealloc)(__unsafe_unretained id, SEL) = NULL;
        __weak typeof(self)weakSelf = self;
        id newDealloc = ^(__unsafe_unretained UIViewController *objSelf){
            [weakSelf _xw_checkDelegate];
            if (originalDealloc == NULL) {
                struct objc_super superInfo = {
                    .receiver = objSelf,
                    .super_class = class_getSuperclass(swizzleClass)
                };
                void (*msgSend)(struct objc_super *, SEL) = (__typeof__(msgSend))objc_msgSendSuper;
                msgSend(&superInfo, deallocSelector);
            }else{
                originalDealloc(objSelf, deallocSelector);
            }
        };
        IMP newDeallocIMP = imp_implementationWithBlock(newDealloc);
        if (!class_addMethod(swizzleClass, deallocSelector, newDeallocIMP, "v@:")) {
            Method deallocMethod = class_getInstanceMethod(swizzleClass, deallocSelector);
            originalDealloc = (void(*)(__unsafe_unretained id, SEL))method_getImplementation(deallocMethod);
            originalDealloc = (void(*)(__unsafe_unretained id, SEL))method_setImplementation(deallocMethod, newDeallocIMP);
        }
    }
}

- (void)_xw_checkDelegate{
    XWTransitionAnimator *animator = objc_getAssociatedObject(self.topViewController, &kXWAnimatorKey);
    if (animator) {
        self.delegate = animator;
    }else{
        self.delegate = nil;
    }
}

- (void)_xw_pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
    XWTransitionAnimator *animator = objc_getAssociatedObject(viewController, &kXWAnimatorKey);
    if (animator) {
        self.delegate = animator;
    }else if([self.delegate isKindOfClass:[XWTransitionAnimator class]]){
        self.delegate = nil;
    }
    [self _xw_pushViewController:viewController animated:animated];
}

@end