mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Purge children from view registry when UIManager is invalidated (#38617)
Summary: Talking about Paper & iOS here. In standard RN applications when a native component is removed permanently from view hierarchy [it is invalidated (if it implements `RCTInvalidating`)](https://github.com/facebook/react-native/blob/e64756ae5bb5c0607a4d97a134620fafcb132b3b/packages/react-native/React/Modules/RCTUIManager.m#L483-L495). Components that implement `RCTInvalidating` such as [`RNSScreenView`](https://github.com/software-mansion/react-native-screens/blob/9fb3bd00850bcdf29b46daa57e56eabda3ae30ea/ios/RNSScreen.mm#L35) of [`react-native-screens`](https://github.com/software-mansion/react-native-screens) library rely on `RCTInvalidating#invalidate` method being called in adequate moment to release retained resources (in my case the `RNSScreenView` holds a strong reference to it's view controller preventing it from being garbage collected). However in case of brownfield applications (React Native is used only for a particular view & loaded on demand, see: https://github.com/software-mansion/react-native-screens/issues/1754 for discussion & app example) when view controller holding `RCTRootView` is dismissed and whole `React Native` managed view / controller tree gets deallocated, `RCTInvalidating#invalidate` method is not called on the dismissed components, thus in my particular use case, leading to memory leak. Right now I've added call to `RCTUIManager#_purgeChildren:fromRegistry:` (which internally invalidates all components which implement `RCTInvalidating`) in `RCTUIManager#invalidate`. ## Changelog: <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [IOS][FIXED] - Purge children from view registry on `RCTUIManager` invalidation. Pull Request resolved: https://github.com/facebook/react-native/pull/38617 Test Plan: You can run the [demo](https://github.com/mkondakov/RNSScreensMemoryLeak) provided in the [issue](https://github.com/software-mansion/react-native-screens/issues/1754). Following screenshots show that memory leak in brownfield application is resolved. Without the change (`invalidate` method is not being called on native components)  With the change:  Reviewed By: NickGerleman Differential Revision: D49952215 Pulled By: javache fbshipit-source-id: 6336b86774615acc40279c97e6ae0bb777bda8ad
This commit is contained in:
committed by
Facebook GitHub Bot
parent
3859eee961
commit
bc63e44b23
@@ -101,8 +101,11 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
RCTExecuteOnMainQueue(^{
|
||||
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"UIManager invalidate", nil);
|
||||
NSMutableDictionary<NSNumber *, id<RCTComponent>> *viewRegistry =
|
||||
(NSMutableDictionary<NSNumber *, id<RCTComponent>> *)self->_viewRegistry;
|
||||
for (NSNumber *rootViewTag in self->_rootViewTags) {
|
||||
UIView *rootView = self->_viewRegistry[rootViewTag];
|
||||
id<RCTComponent> rootView = viewRegistry[rootViewTag];
|
||||
[self _purgeChildren:[rootView reactSubviews] fromRegistry:viewRegistry];
|
||||
if ([rootView conformsToProtocol:@protocol(RCTInvalidating)]) {
|
||||
[(id<RCTInvalidating>)rootView invalidate];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user