Leaking views when changing rootViewController inside transitionWithView

前端 未结 5 1718
陌清茗
陌清茗 2020-12-04 05:29

While investigating a memory leak I discovered a problem related to the technique of calling setRootViewController: inside a transition animation block:

5条回答
  •  借酒劲吻你
    2020-12-04 06:10

    I faced this issue and it annoyed me for a whole day. I've tried @Rich's obj-c solution and it turns out when I want to present another viewController after that, I will be blocked with a blank UITransitionView.

    Finally, I figured out this way and it worked for me.

    - (void)setRootViewController:(UIViewController *)rootViewController {
        // dismiss presented view controllers before switch rootViewController to avoid messed up view hierarchy, or even crash
        UIViewController *presentedViewController = [self findPresentedViewControllerStartingFrom:self.window.rootViewController];
        [self dismissPresentedViewController:presentedViewController completionBlock:^{
            [self.window setRootViewController:rootViewController];
        }];
    }
    
    - (void)dismissPresentedViewController:(UIViewController *)vc completionBlock:(void(^)())completionBlock {
        // if vc is presented by other view controller, dismiss it.
        if ([vc presentingViewController]) {
            __block UIViewController* nextVC = vc.presentingViewController;
            [vc dismissViewControllerAnimated:NO completion:^ {
                // if the view controller which is presenting vc is also presented by other view controller, dismiss it
                if ([nextVC presentingViewController]) {
                    [self dismissPresentedViewController:nextVC completionBlock:completionBlock];
                } else {
                    if (completionBlock != nil) {
                        completionBlock();
                    }
                }
            }];
        } else {
            if (completionBlock != nil) {
                completionBlock();
            }
        }
    }
    
    + (UIViewController *)findPresentedViewControllerStartingFrom:(UIViewController *)start {
        if ([start isKindOfClass:[UINavigationController class]]) {
            return [self findPresentedViewControllerStartingFrom:[(UINavigationController *)start topViewController]];
        }
    
        if ([start isKindOfClass:[UITabBarController class]]) {
            return [self findPresentedViewControllerStartingFrom:[(UITabBarController *)start selectedViewController]];
        }
    
        if (start.presentedViewController == nil || start.presentedViewController.isBeingDismissed) {
            return start;
        }
    
        return [self findPresentedViewControllerStartingFrom:start.presentedViewController];
    }
    

    Alright, now all you have to do is call [self setRootViewController:newViewController]; when you want to switch root view controller.

提交回复
热议问题