Skip to content

Commit 8ad8107

Browse files
fkgozalifacebook-github-bot
authored andcommitted
iOS: when the bridge has been invalidated, NativeModule lookup should just return nil
Summary: There's a corner case where: * The bridge gets invalidated, and native modules are cleaning up themselves (but not done yet) * Something asks for a NativeModule instance - ideally it should just get nil at this point * If TM Manager is invalidating, we get nil correctly, but we continue thru the old NativeModule lookup logic * The latter will fail anyway, and would throw a redbox (RCTLogError). So, if the bridge is invalidated, if TM Manager returns nil, we should just return nil for old NativeModule lookup. The module of interest is RCTImageLoader, which was requested by RCTImageView on deallocation. The problem is RCTImageView got dealloc'ed **after** the bridge has been invalidated, so the lookup would always fail... Bonus: RCTImageView should just keep a weak ref to the RCTImageLoader, so that: * if the imageLoader is still alive on image dealloc, it can still access them (last minute "meaningless" cleanup) * if the imageLoader is gone, then the image deallocation doesn't do anything Changelog: [iOS] [Fixed] - Fix module lookup race condition on bridge invalidation. Reviewed By: p-sun, sammy-SC Differential Revision: D21371845 fbshipit-source-id: 862dc07de18ddbfb90e87e24b8dbd001147ddce4
1 parent 1787c16 commit 8ad8107

File tree

2 files changed

+16
-8
lines changed

2 files changed

+16
-8
lines changed

Libraries/Image/RCTImageView.mm

+11-8
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ @implementation RCTImageView
6464
// Weak reference back to the bridge, for image loading
6565
__weak RCTBridge *_bridge;
6666

67+
// Weak reference back to the active image loader.
68+
__weak id<RCTImageLoaderWithAttributionProtocol> _imageLoader;
69+
6770
// The image source that's currently displayed
6871
RCTImageSource *_imageSource;
6972

@@ -327,11 +330,13 @@ - (void)reloadImage
327330
[weakSelf imageLoaderLoadedImage:loadedImage error:error forImageSource:source partial:NO];
328331
};
329332

330-
id<RCTImageLoaderWithAttributionProtocol> imageLoader = [_bridge moduleForName:@"ImageLoader"
331-
lazilyLoadIfNecessary:YES];
332-
RCTImageURLLoaderRequest *loaderRequest = [imageLoader loadImageWithURLRequest:source.request
333-
size:imageSize
334-
scale:imageScale
333+
if (!_imageLoader) {
334+
_imageLoader = [_bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES];
335+
}
336+
337+
RCTImageURLLoaderRequest *loaderRequest = [_imageLoader loadImageWithURLRequest:source.request
338+
size:imageSize
339+
scale:imageScale
335340
clipped:NO
336341
resizeMode:_resizeMode
337342
attribution:{
@@ -470,9 +475,7 @@ - (void)didMoveToWindow
470475
}
471476

472477
- (void)dealloc {
473-
id<RCTImageLoaderWithAttributionProtocol> imageLoader = [_bridge moduleForName:@"ImageLoader"
474-
lazilyLoadIfNecessary:YES];
475-
[imageLoader trackURLImageDidDestroy:_loaderRequest];
478+
[_imageLoader trackURLImageDidDestroy:_loaderRequest];
476479
}
477480

478481
@end

React/CxxBridge/RCTCxxBridge.mm

+5
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,11 @@ - (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoa
488488
}
489489

490490
// Module may not be loaded yet, so attempt to force load it here.
491+
// Do this only if the bridge is still valid.
492+
if (_didInvalidate) {
493+
return nil;
494+
}
495+
491496
const BOOL result = [self.delegate respondsToSelector:@selector(bridge:didNotFindModule:)] &&
492497
[self.delegate bridge:self didNotFindModule:moduleName];
493498
if (result) {

0 commit comments

Comments
 (0)