mirror of
https://github.com/status-im/react-native.git
synced 2025-02-25 15:45:32 +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)
|
selector:@selector(reload)
|
||||||
name:RCTReloadNotification
|
name:RCTReloadNotification
|
||||||
object:nil];
|
object:nil];
|
||||||
;
|
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
@ -619,6 +618,8 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||||||
- (void)bindKeys
|
- (void)bindKeys
|
||||||
{
|
{
|
||||||
#if TARGET_IPHONE_SIMULATOR
|
#if TARGET_IPHONE_SIMULATOR
|
||||||
|
__weak RCTBridge *weakSelf = self;
|
||||||
|
|
||||||
// Workaround around the first cmd+r not working: http://openradar.appspot.com/19613391
|
// 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
|
// You can register just the cmd key and do nothing. This will trigger the bug and cmd+r
|
||||||
// will work like a charm!
|
// will work like a charm!
|
||||||
@ -627,27 +628,33 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||||||
action:^(UIKeyCommand *command) {
|
action:^(UIKeyCommand *command) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"r"
|
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"r"
|
||||||
modifierFlags:UIKeyModifierCommand
|
modifierFlags:UIKeyModifierCommand
|
||||||
action:^(UIKeyCommand *command) {
|
action:^(UIKeyCommand *command) {
|
||||||
[self reload];
|
[weakSelf reload];
|
||||||
}];
|
}];
|
||||||
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"n"
|
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"n"
|
||||||
modifierFlags:UIKeyModifierCommand
|
modifierFlags:UIKeyModifierCommand
|
||||||
action:^(UIKeyCommand *command) {
|
action:^(UIKeyCommand *command) {
|
||||||
_executorClass = Nil;
|
RCTBridge *strongSelf = weakSelf;
|
||||||
[self reload];
|
if (!strongSelf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strongSelf->_executorClass = Nil;
|
||||||
|
[strongSelf reload];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"d"
|
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"d"
|
||||||
modifierFlags:UIKeyModifierCommand
|
modifierFlags:UIKeyModifierCommand
|
||||||
action:^(UIKeyCommand *command) {
|
action:^(UIKeyCommand *command) {
|
||||||
_executorClass = NSClassFromString(@"RCTWebSocketExecutor");
|
RCTBridge *strongSelf = weakSelf;
|
||||||
if (!_executorClass) {
|
if (!strongSelf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strongSelf->_executorClass = NSClassFromString(@"RCTWebSocketExecutor");
|
||||||
|
if (!strongSelf->_executorClass) {
|
||||||
RCTLogError(@"WebSocket debugger is not available. Did you forget to include RCTWebSocketExecutor?");
|
RCTLogError(@"WebSocket debugger is not available. Did you forget to include RCTWebSocketExecutor?");
|
||||||
}
|
}
|
||||||
[self reload];
|
[strongSelf reload];
|
||||||
}];
|
}];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -662,7 +669,7 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
RCTAssert(!self.valid, @"must call -invalidate before -dealloc");
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - RCTInvalidating
|
#pragma mark - RCTInvalidating
|
||||||
@ -674,6 +681,15 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||||||
|
|
||||||
- (void)invalidate
|
- (void)invalidate
|
||||||
{
|
{
|
||||||
|
if (!self.isValid && _modulesByID == nil) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![NSThread isMainThread]) {
|
||||||
|
[self performSelectorOnMainThread:@selector(invalidate) withObject:nil waitUntilDone:YES];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
|
||||||
// Wait for queued methods to finish
|
// 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.
|
* will be set automatically by the bridge when it initializes the module.
|
||||||
* To implement this in your module, just add @synthesize bridge = _bridge;
|
* 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
|
* The module name exposed to JS. If omitted, this will be inferred
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
@implementation RCTJavaScriptLoader
|
@implementation RCTJavaScriptLoader
|
||||||
{
|
{
|
||||||
RCTBridge *_bridge;
|
__weak RCTBridge *_bridge;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,19 +92,6 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
|||||||
- (void)setUp
|
- (void)setUp
|
||||||
{
|
{
|
||||||
if (!_registered) {
|
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
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(reload)
|
selector:@selector(reload)
|
||||||
name:RCTReloadViewsNotification
|
name:RCTReloadViewsNotification
|
||||||
@ -122,9 +109,9 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
|||||||
|
|
||||||
- (void)tearDown
|
- (void)tearDown
|
||||||
{
|
{
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
if (_registered) {
|
if (_registered) {
|
||||||
_registered = NO;
|
_registered = NO;
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
||||||
[_contentView removeGestureRecognizer:_touchHandler];
|
[_contentView removeGestureRecognizer:_touchHandler];
|
||||||
[_contentView removeFromSuperview];
|
[_contentView removeFromSuperview];
|
||||||
[_touchHandler invalidate];
|
[_touchHandler invalidate];
|
||||||
@ -174,6 +161,19 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
|||||||
{
|
{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
_registered = YES;
|
_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 ?: @"";
|
NSString *moduleName = _moduleName ?: @"";
|
||||||
NSDictionary *appParameters = @{
|
NSDictionary *appParameters = @{
|
||||||
@"rootTag": _contentView.reactTag,
|
@"rootTag": _contentView.reactTag,
|
||||||
@ -197,7 +197,7 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
|||||||
- (void)setFrame:(CGRect)frame
|
- (void)setFrame:(CGRect)frame
|
||||||
{
|
{
|
||||||
[super setFrame:frame];
|
[super setFrame:frame];
|
||||||
_contentView.frame = self.bounds;
|
_contentView.frame = (CGRect){CGPointZero, frame.size};
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reload
|
- (void)reload
|
||||||
|
@ -167,14 +167,15 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||||||
|
|
||||||
- (void)invalidate
|
- (void)invalidate
|
||||||
{
|
{
|
||||||
|
if (self.isValid) {
|
||||||
if ([NSThread currentThread] != _javaScriptThread) {
|
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:NO];
|
||||||
[self performSelector:@selector(invalidate) onThread:_javaScriptThread withObject:nil waitUntilDone:YES];
|
} else {
|
||||||
} else if (_context != NULL) {
|
|
||||||
JSGlobalContextRelease(_context);
|
JSGlobalContextRelease(_context);
|
||||||
_context = NULL;
|
_context = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
|
@ -177,7 +177,7 @@ static UIViewAnimationCurve UIViewAnimationCurveFromRCTAnimationType(RCTAnimatio
|
|||||||
|
|
||||||
@implementation RCTUIManager
|
@implementation RCTUIManager
|
||||||
{
|
{
|
||||||
dispatch_queue_t _shadowQueue;
|
__weak dispatch_queue_t _shadowQueue;
|
||||||
|
|
||||||
// Root views are only mutated on the shadow queue
|
// Root views are only mutated on the shadow queue
|
||||||
NSMutableSet *_rootViewTags;
|
NSMutableSet *_rootViewTags;
|
||||||
@ -319,7 +319,6 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName)
|
|||||||
|
|
||||||
// Register shadow view
|
// Register shadow view
|
||||||
dispatch_async(_shadowQueue, ^{
|
dispatch_async(_shadowQueue, ^{
|
||||||
|
|
||||||
RCTShadowView *shadowView = [[RCTShadowView alloc] init];
|
RCTShadowView *shadowView = [[RCTShadowView alloc] init];
|
||||||
shadowView.reactTag = reactTag;
|
shadowView.reactTag = reactTag;
|
||||||
shadowView.frame = frame;
|
shadowView.frame = frame;
|
||||||
@ -934,11 +933,9 @@ static void RCTMeasureLayout(RCTShadowView *view,
|
|||||||
RCTResponseSenderBlock callback)
|
RCTResponseSenderBlock callback)
|
||||||
{
|
{
|
||||||
if (!view) {
|
if (!view) {
|
||||||
RCTLogError(@"Attempting to measure view that does not exist");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!ancestor) {
|
if (!ancestor) {
|
||||||
RCTLogError(@"Attempting to measure relative to ancestor that does not exist");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CGRect result = [view measureLayoutRelativeToAncestor:ancestor];
|
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
|
* allowing the manager (or the views that it manages) to manipulate the view
|
||||||
* hierarchy and send events back to the JS context.
|
* 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
|
* The module name exposed to React JS. If omitted, this will be inferred
|
||||||
|
Loading…
x
Reference in New Issue
Block a user