Skip to content

Commit 4fa2fb6

Browse files
philIipfacebook-github-bot
authored andcommitted
weakly hold key window for KVO frame listener
Summary: Changelog: [Internal] RCTDeviceInfo uses KVO to listen to frame changes in the application's keyWindow. On initialization, it reads the global keyWindow and adds itself as a listener. When RCTDeviceInfo is cleaned up, it reads the global keyWindow again, and removes itself as an observer. However, this makes an assumption that the keyWindow is always the same. This is not always true - for example, when a UIAlert is presented, the OS creates a new temporary keyWindow to host the alert in order to make sure it is the first responder. If the cleanup is called then, the app will crash because there is no RCTDeviceInfo observing it. Another example is the LogBox, which also temporarily creates a new keyWindow. The fix is simple, we can capture a reference to the application's keyWindow on initialization, but make sure it is weakly held as the keyWindow is usually managed by iOS. Then, when we remove the listener, it is always guaranteed it is the window that we are observing. Reviewed By: javache, cipolleschi, realsoelynn Differential Revision: D71667722
1 parent e797b16 commit 4fa2fb6

File tree

1 file changed

+5
-2
lines changed

1 file changed

+5
-2
lines changed

packages/react-native/React/CoreModules/RCTDeviceInfo.mm

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ @implementation RCTDeviceInfo {
3030
BOOL _isFullscreen;
3131
std::atomic<BOOL> _invalidated;
3232
NSDictionary *_constants;
33+
34+
__weak UIWindow *_applicationWindow;
3335
}
3436

3537
static NSString *const kFrameKeyPath = @"frame";
@@ -41,7 +43,8 @@ @implementation RCTDeviceInfo {
4143
- (instancetype)init
4244
{
4345
if (self = [super init]) {
44-
[RCTKeyWindow() addObserver:self forKeyPath:kFrameKeyPath options:NSKeyValueObservingOptionNew context:nil];
46+
_applicationWindow = RCTKeyWindow();
47+
[_applicationWindow addObserver:self forKeyPath:kFrameKeyPath options:NSKeyValueObservingOptionNew context:nil];
4548
}
4649
return self;
4750
}
@@ -141,7 +144,7 @@ - (void)_cleanupObservers
141144

142145
[[NSNotificationCenter defaultCenter] removeObserver:self name:RCTBridgeWillInvalidateModulesNotification object:nil];
143146

144-
[RCTKeyWindow() removeObserver:self forKeyPath:kFrameKeyPath];
147+
[_applicationWindow removeObserver:self forKeyPath:kFrameKeyPath];
145148

146149
#if TARGET_OS_IOS
147150
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];

0 commit comments

Comments
 (0)