From 33c16689a88aee234fd482baf854f6de96d34ddd Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Wed, 26 Aug 2020 18:47:28 -0700 Subject: [PATCH] Deallocate UIViewController after it was used in Modal component Summary: Changelog: [Internal] # Problem `RCTModalHostViewComponentView` reuses the same UIViewController between recycles. This can be a problem if dismissal of the modal is animated as the UIViewController is still presented while it is being dismissed. That's when "Application tried to present modally an active controller" exception can happen. # Solution Deallocate UIViewController when `RCTModalHostViewComponentView` is recycled. Reviewed By: PeteTheHeat Differential Revision: D23345711 fbshipit-source-id: da540571184afcb88b52758c4a1f0b4ec5874eb1 --- .../Modal/RCTModalHostViewComponentView.mm | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm index dfe980c3679..b4a8b7b2f52 100644 --- a/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm @@ -111,15 +111,23 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct( static const auto defaultProps = std::make_shared(); _props = defaultProps; _shouldAnimatePresentation = YES; - _viewController = [RCTFabricModalHostViewController new]; - _viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical; - _viewController.delegate = self; + _isPresented = NO; } return self; } +- (RCTFabricModalHostViewController *)viewController +{ + if (!_viewController) { + _viewController = [RCTFabricModalHostViewController new]; + _viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical; + _viewController.delegate = self; + } + return _viewController; +} + - (void)presentViewController:(UIViewController *)modalViewController animated:(BOOL)animated completion:(void (^)(void))completion @@ -138,7 +146,7 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct( BOOL shouldBePresented = !_isPresented && self.window; if (shouldBePresented) { _isPresented = YES; - [self presentViewController:_viewController + [self presentViewController:self.viewController animated:_shouldAnimatePresentation completion:^{ if (!self->_eventEmitter) { @@ -155,7 +163,7 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct( BOOL shouldBeHidden = _isPresented && !self.superview; if (shouldBeHidden) { _isPresented = NO; - [self dismissViewController:_viewController animated:_shouldAnimatePresentation]; + [self dismissViewController:self.viewController animated:_shouldAnimatePresentation]; } } @@ -197,6 +205,7 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct( { [super prepareForRecycle]; _stateTeller.invalidate(); + _viewController = nil; _isPresented = NO; } @@ -205,14 +214,14 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct( const auto &newProps = *std::static_pointer_cast(props); #if !TARGET_OS_TV - _viewController.supportedInterfaceOrientations = supportedOrientationsMask(newProps.supportedOrientations); + self.viewController.supportedInterfaceOrientations = supportedOrientationsMask(newProps.supportedOrientations); #endif std::tuple result = animationConfiguration(newProps.animationType); _shouldAnimatePresentation = std::get<0>(result); - _viewController.modalTransitionStyle = std::get<1>(result); + self.viewController.modalTransitionStyle = std::get<1>(result); - _viewController.modalPresentationStyle = presentationConfiguration(newProps); + self.viewController.modalPresentationStyle = presentationConfiguration(newProps); [super updateProps:props oldProps:oldProps]; } @@ -224,7 +233,7 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct( - (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index { - [_viewController.view insertSubview:childComponentView atIndex:index]; + [self.viewController.view insertSubview:childComponentView atIndex:index]; } - (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index