mirror of
https://github.com/status-im/react-native.git
synced 2025-02-25 07:35:25 +00:00
[ReactNative] Remove bridge retaining cycles
This commit is contained in:
parent
72390239be
commit
6854da9b86
@ -610,7 +610,6 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||
selector:@selector(reload)
|
||||
name:RCTReloadNotification
|
||||
object:nil];
|
||||
;
|
||||
}
|
||||
}];
|
||||
}
|
||||
@ -619,6 +618,8 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||
- (void)bindKeys
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
__weak RCTBridge *weakSelf = self;
|
||||
|
||||
// Workaround around the first cmd+r not working: http://openradar.appspot.com/19613391
|
||||
// You can register just the cmd key and do nothing. This will trigger the bug and cmd+r
|
||||
// will work like a charm!
|
||||
@ -627,27 +628,33 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||
action:^(UIKeyCommand *command) {
|
||||
// Do nothing
|
||||
}];
|
||||
|
||||
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"r"
|
||||
modifierFlags:UIKeyModifierCommand
|
||||
action:^(UIKeyCommand *command) {
|
||||
[self reload];
|
||||
[weakSelf reload];
|
||||
}];
|
||||
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"n"
|
||||
modifierFlags:UIKeyModifierCommand
|
||||
action:^(UIKeyCommand *command) {
|
||||
_executorClass = Nil;
|
||||
[self reload];
|
||||
RCTBridge *strongSelf = weakSelf;
|
||||
if (!strongSelf) {
|
||||
return;
|
||||
}
|
||||
strongSelf->_executorClass = Nil;
|
||||
[strongSelf reload];
|
||||
}];
|
||||
|
||||
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"d"
|
||||
modifierFlags:UIKeyModifierCommand
|
||||
action:^(UIKeyCommand *command) {
|
||||
_executorClass = NSClassFromString(@"RCTWebSocketExecutor");
|
||||
if (!_executorClass) {
|
||||
RCTBridge *strongSelf = weakSelf;
|
||||
if (!strongSelf) {
|
||||
return;
|
||||
}
|
||||
strongSelf->_executorClass = NSClassFromString(@"RCTWebSocketExecutor");
|
||||
if (!strongSelf->_executorClass) {
|
||||
RCTLogError(@"WebSocket debugger is not available. Did you forget to include RCTWebSocketExecutor?");
|
||||
}
|
||||
[self reload];
|
||||
[strongSelf reload];
|
||||
}];
|
||||
#endif
|
||||
}
|
||||
@ -662,7 +669,7 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
RCTAssert(!self.valid, @"must call -invalidate before -dealloc");
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
#pragma mark - RCTInvalidating
|
||||
@ -674,6 +681,15 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
if (!self.isValid && _modulesByID == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (![NSThread isMainThread]) {
|
||||
[self performSelectorOnMainThread:@selector(invalidate) withObject:nil waitUntilDone:YES];
|
||||
return;
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
// Wait for queued methods to finish
|
||||
|
@ -31,7 +31,7 @@ typedef void (^RCTResponseSenderBlock)(NSArray *response);
|
||||
* will be set automatically by the bridge when it initializes the module.
|
||||
* To implement this in your module, just add @synthesize bridge = _bridge;
|
||||
*/
|
||||
@property (nonatomic, strong) RCTBridge *bridge;
|
||||
@property (nonatomic, weak) RCTBridge *bridge;
|
||||
|
||||
/**
|
||||
* The module name exposed to JS. If omitted, this will be inferred
|
||||
|
@ -24,7 +24,7 @@
|
||||
*/
|
||||
@implementation RCTJavaScriptLoader
|
||||
{
|
||||
RCTBridge *_bridge;
|
||||
__weak RCTBridge *_bridge;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,19 +92,6 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
||||
- (void)setUp
|
||||
{
|
||||
if (!_registered) {
|
||||
/**
|
||||
* Every root view that is created must have a unique react tag.
|
||||
* Numbering of these tags goes from 1, 11, 21, 31, etc
|
||||
*
|
||||
* NOTE: Since the bridge persists, the RootViews might be reused, so now
|
||||
* the react tag is assigned every time we load new content.
|
||||
*/
|
||||
_contentView = [[UIView alloc] init];
|
||||
_contentView.reactTag = [_bridge.uiManager allocateRootTag];
|
||||
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
|
||||
[_contentView addGestureRecognizer:_touchHandler];
|
||||
[self addSubview:_contentView];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(reload)
|
||||
name:RCTReloadViewsNotification
|
||||
@ -122,9 +109,9 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
if (_registered) {
|
||||
_registered = NO;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[_contentView removeGestureRecognizer:_touchHandler];
|
||||
[_contentView removeFromSuperview];
|
||||
[_touchHandler invalidate];
|
||||
@ -174,6 +161,19 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
_registered = YES;
|
||||
/**
|
||||
* Every root view that is created must have a unique react tag.
|
||||
* Numbering of these tags goes from 1, 11, 21, 31, etc
|
||||
*
|
||||
* NOTE: Since the bridge persists, the RootViews might be reused, so now
|
||||
* the react tag is assigned every time we load new content.
|
||||
*/
|
||||
_contentView = [[UIView alloc] initWithFrame:self.bounds];
|
||||
_contentView.reactTag = [_bridge.uiManager allocateRootTag];
|
||||
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
|
||||
[_contentView addGestureRecognizer:_touchHandler];
|
||||
[self addSubview:_contentView];
|
||||
|
||||
NSString *moduleName = _moduleName ?: @"";
|
||||
NSDictionary *appParameters = @{
|
||||
@"rootTag": _contentView.reactTag,
|
||||
@ -197,7 +197,7 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
||||
- (void)setFrame:(CGRect)frame
|
||||
{
|
||||
[super setFrame:frame];
|
||||
_contentView.frame = self.bounds;
|
||||
_contentView.frame = (CGRect){CGPointZero, frame.size};
|
||||
}
|
||||
|
||||
- (void)reload
|
||||
|
@ -167,12 +167,13 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
if ([NSThread currentThread] != _javaScriptThread) {
|
||||
// Yes, block until done. If we're getting called right before dealloc, it's the only safe option.
|
||||
[self performSelector:@selector(invalidate) onThread:_javaScriptThread withObject:nil waitUntilDone:YES];
|
||||
} else if (_context != NULL) {
|
||||
JSGlobalContextRelease(_context);
|
||||
_context = NULL;
|
||||
if (self.isValid) {
|
||||
if ([NSThread currentThread] != _javaScriptThread) {
|
||||
[self performSelector:@selector(invalidate) onThread:_javaScriptThread withObject:nil waitUntilDone:NO];
|
||||
} else {
|
||||
JSGlobalContextRelease(_context);
|
||||
_context = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ static UIViewAnimationCurve UIViewAnimationCurveFromRCTAnimationType(RCTAnimatio
|
||||
|
||||
@implementation RCTUIManager
|
||||
{
|
||||
dispatch_queue_t _shadowQueue;
|
||||
__weak dispatch_queue_t _shadowQueue;
|
||||
|
||||
// Root views are only mutated on the shadow queue
|
||||
NSMutableSet *_rootViewTags;
|
||||
@ -319,7 +319,6 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName)
|
||||
|
||||
// Register shadow view
|
||||
dispatch_async(_shadowQueue, ^{
|
||||
|
||||
RCTShadowView *shadowView = [[RCTShadowView alloc] init];
|
||||
shadowView.reactTag = reactTag;
|
||||
shadowView.frame = frame;
|
||||
@ -934,11 +933,9 @@ static void RCTMeasureLayout(RCTShadowView *view,
|
||||
RCTResponseSenderBlock callback)
|
||||
{
|
||||
if (!view) {
|
||||
RCTLogError(@"Attempting to measure view that does not exist");
|
||||
return;
|
||||
}
|
||||
if (!ancestor) {
|
||||
RCTLogError(@"Attempting to measure relative to ancestor that does not exist");
|
||||
return;
|
||||
}
|
||||
CGRect result = [view measureLayoutRelativeToAncestor:ancestor];
|
||||
|
@ -28,7 +28,7 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, RCTSparseArray *v
|
||||
* allowing the manager (or the views that it manages) to manipulate the view
|
||||
* hierarchy and send events back to the JS context.
|
||||
*/
|
||||
@property (nonatomic, strong) RCTBridge *bridge;
|
||||
@property (nonatomic, weak) RCTBridge *bridge;
|
||||
|
||||
/**
|
||||
* The module name exposed to React JS. If omitted, this will be inferred
|
||||
|
Loading…
x
Reference in New Issue
Block a user