diff --git a/ios/RNSScreen.mm b/ios/RNSScreen.mm index cd8b60fcbd..1673de6e3b 100644 --- a/ios/RNSScreen.mm +++ b/ios/RNSScreen.mm @@ -550,6 +550,17 @@ - (void)prepareForRecycle _dismissed = NO; _state.reset(); _touchHandler = nil; + + // We set this prop to default value here to workaround view-recycling. + // Let's assume the view has had _stackPresentation == set + // before below line was executed. Then, when instantiated again (with the same modal presentation) + // updateProps:oldProps: method would be called and setter for stack presentation would not be called. + // This is crucial as in that setter we register `self.controller` as a delegate + // (UIAdaptivePresentationControllerDelegate) to presentation controller and this leads to buggy modal behaviour as we + // rely on UIAdaptivePresentationControllerDelegate callbacks. Restoring the default value and then comparing against + // it in updateProps:oldProps: allows for setter to be called, however if there was some additional logic to execute + // when stackPresentation is set to "push" the setter would not be triggered. + _stackPresentation = RNSScreenStackPresentationPush; } - (void)updateProps:(facebook::react::Props::Shared const &)props @@ -603,9 +614,12 @@ - (void)updateProps:(facebook::react::Props::Shared const &)props } #endif - if (newScreenProps.stackPresentation != oldScreenProps.stackPresentation) { - [self - setStackPresentation:[RNSConvert RNSScreenStackPresentationFromCppEquivalent:newScreenProps.stackPresentation]]; + // Notice that we compare against _stackPresentation, not oldScreenProps.stackPresentation. + // See comment in prepareForRecycle method for explanation. + RNSScreenStackPresentation newStackPresentation = + [RNSConvert RNSScreenStackPresentationFromCppEquivalent:newScreenProps.stackPresentation]; + if (newStackPresentation != _stackPresentation) { + [self setStackPresentation:newStackPresentation]; } if (newScreenProps.stackAnimation != oldScreenProps.stackAnimation) {