From b29e634e2631550b647a529612e6ab1c172f7f9a Mon Sep 17 00:00:00 2001 From: Krzysztof Magiera Date: Fri, 21 Feb 2020 22:40:44 +0100 Subject: [PATCH] =?UTF-8?q?Fix=20appear/disappear=20events=20for=20ScreenC?= =?UTF-8?q?ontainer=20and=20address=20memo=E2=80=A6=20(#354)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This chnage fixes the way we'd managed parent<>child VC relation. With this change in we hook child VC to parent in didMoveToWindow to match Stack behavior. We also wait with updating child view frame untill the child screen is attached. Finally we utilize RCTInvalidating interface to spot moments when screen controller is unmounted from react such that we can break reference cycle between screen and screen view (we don't do it in invalidate directly as sometimes we need to wait till transition end). --- ios/RNSScreen.m | 41 +++++++++++++++++++++++++++------------- ios/RNSScreenContainer.m | 23 +++++++++++++++++++--- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/ios/RNSScreen.m b/ios/RNSScreen.m index 68cf43b9..3d7a166e 100644 --- a/ios/RNSScreen.m +++ b/ios/RNSScreen.m @@ -8,7 +8,13 @@ #import #import -@interface RNSScreenView () +@interface RNSScreen () + +- (void)invalidate; + +@end + +@interface RNSScreenView () @end @implementation RNSScreenView { @@ -231,18 +237,24 @@ } } +- (void)invalidate +{ + [_controller invalidate]; +} + @end @implementation RNSScreen { - __weak UIView *_view; __weak id _previousFirstResponder; CGRect _lastViewFrame; + BOOL disappeared; + BOOL invalidated; } - (instancetype)initWithView:(UIView *)view { if (self = [super init]) { - _view = view; + self.view = view; } return self; } @@ -289,12 +301,23 @@ // screen dismissed, send event [((RNSScreenView *)self.view) notifyDismissed]; } - _view = self.view; - self.view = nil; + disappeared = YES; + if (invalidated) { + self.view = nil; + } +} + +- (void)invalidate +{ + if (disappeared) { + self.view = nil; + } + invalidated = YES; } - (void)viewDidAppear:(BOOL)animated { + disappeared = NO; [super viewDidAppear:animated]; [((RNSScreenView *)self.view) notifyAppear]; } @@ -305,14 +328,6 @@ _previousFirstResponder = nil; } -- (void)loadView -{ - if (_view != nil) { - self.view = _view; - _view = nil; - } -} - @end @implementation RNSScreenManager diff --git a/ios/RNSScreenContainer.m b/ios/RNSScreenContainer.m index bdf1f818..e7848510 100644 --- a/ios/RNSScreenContainer.m +++ b/ios/RNSScreenContainer.m @@ -11,7 +11,7 @@ @end -@interface RNSScreenContainerView () +@interface RNSScreenContainerView () @property (nonatomic, retain) UIViewController *controller; @property (nonatomic, retain) NSMutableSet *activeScreens; @@ -54,7 +54,6 @@ { subview.reactSuperview = self; [_reactSubviews insertObject:subview atIndex:atIndex]; - subview.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height); } - (void)removeReactSubview:(RNSScreenView *)subview @@ -68,6 +67,11 @@ return _reactSubviews; } +- (UIViewController *)reactViewController +{ + return _controller; +} + - (void)detachScreen:(RNSScreenView *)screen { [screen.controller willMoveToParentViewController:nil]; @@ -79,6 +83,7 @@ - (void)attachScreen:(RNSScreenView *)screen { [_controller addChildViewController:screen.controller]; + screen.controller.view.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height); [_controller.view addSubview:screen.controller.view]; [screen.controller didMoveToParentViewController:_controller]; [_activeScreens addObject:screen]; @@ -155,10 +160,22 @@ [self markChildUpdated]; } +- (void)didMoveToWindow +{ + if (self.window) { + [self reactAddControllerToClosestParent:_controller]; + } +} + +- (void)invalidate +{ + [_controller willMoveToParentViewController:nil]; + [_controller removeFromParentViewController]; +} + - (void)layoutSubviews { [super layoutSubviews]; - [self reactAddControllerToClosestParent:_controller]; _controller.view.frame = self.bounds; for (RNSScreenView *subview in _reactSubviews) { subview.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);