Skip to content

Commit

Permalink
Fix updating push native stack to avoid mid-transition related b… (#347)
Browse files Browse the repository at this point in the history
This change addresses two problem. First was related to header subviews that were not laid out properly before we installed them in the header. This was causing occasional bugs where the header subviews were misplaced. The fix was to enforce container update run after layout is done (we enqueue update on ui thread directly from didUpdateReactSubviews).

The second problem was related to UINavController nlifecycle methods not triggering correctly in case when updates are being made to the nav controller which isn't mounted. Previously we fixed similar issue for modal controllers where because of the fact container wasn't mounted we couldn't run modal screen updates. With push controllers the problem is very similar however the VC do update just stop getting proper lifecycle updates and warning "Unbalanced calls to begin/end appearance transitions" is displayed. The fix was similar as in the modal case, that is, we wait until container is installed in window.
  • Loading branch information
kmagiera committed Feb 19, 2020
1 parent 26d8dc2 commit 0e00f49
Showing 1 changed file with 12 additions and 3 deletions.
15 changes: 12 additions & 3 deletions ios/RNSScreenStack.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ - (instancetype)initWithOperation:(UINavigationControllerOperation)operation;
@end

@implementation RNSScreenStackView {
BOOL _needUpdate;
UINavigationController *_controller;
NSMutableArray<RNSScreenView *> *_reactSubviews;
NSMutableSet<RNSScreenView *> *_dismissedScreens;
Expand All @@ -38,7 +37,6 @@ - (instancetype)initWithManager:(RNSScreenStackManager*)manager
_dismissedScreens = [NSMutableSet new];
_controller = [[UINavigationController alloc] init];
_controller.delegate = self;
_needUpdate = NO;
[self addSubview:_controller.view];
_controller.interactivePopGestureRecognizer.delegate = self;

Expand Down Expand Up @@ -164,7 +162,12 @@ - (void)removeReactSubview:(RNSScreenView *)subview

- (void)didUpdateReactSubviews
{
[self updateContainer];
// we need to wait until children have their layout set. At this point they don't have the layout
// set yet, however the layout call is already enqueued on ui thread. Enqueuing update call on the
// ui queue will guarantee that the update will run after layout.
dispatch_async(dispatch_get_main_queue(), ^{
[self updateContainer];
});
}

- (void)didMoveToWindow
Expand Down Expand Up @@ -281,6 +284,12 @@ - (void)setPushViewControllers:(NSArray<UIViewController *> *)controllers
return;
}

// if view controller is not yet attached to window we skip updates now and run them when view
// is attached
if (self.window == nil) {
return;
}

UIViewController *top = controllers.lastObject;
UIViewController *lastTop = _controller.viewControllers.lastObject;

Expand Down

0 comments on commit 0e00f49

Please sign in to comment.