Skip to content

Commit 5ce9fa4

Browse files
committed
Changed default method queue to a background queue.
1 parent 5e2f90a commit 5ce9fa4

9 files changed

Lines changed: 78 additions & 32 deletions

File tree

Libraries/ActionSheetIOS/RCTActionSheetManager.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ - (instancetype)init
3030
return self;
3131
}
3232

33+
- (dispatch_queue_t)methodQueue
34+
{
35+
return dispatch_get_main_queue();
36+
}
37+
3338
RCT_EXPORT_METHOD(showActionSheetWithOptions:(NSDictionary *)options
3439
failureCallback:(RCTResponseSenderBlock)failureCallback
3540
successCallback:(RCTResponseSenderBlock)successCallback)

Libraries/Geolocation/RCTLocationObserver.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ - (void)dealloc
128128
_locationManager.delegate = nil;
129129
}
130130

131+
- (dispatch_queue_t)methodQueue
132+
{
133+
return dispatch_get_main_queue();
134+
}
135+
131136
#pragma mark - Private API
132137

133138
- (void)beginLocationUpdates

Libraries/LinkingIOS/RCTLinkingManager.m

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ - (void)dealloc
3636
[[NSNotificationCenter defaultCenter] removeObserver:self];
3737
}
3838

39+
- (dispatch_queue_t)methodQueue
40+
{
41+
return dispatch_queue_create("com.facebook.React.LinkingManager", DISPATCH_QUEUE_SERIAL);
42+
}
43+
3944
+ (BOOL)application:(UIApplication *)application
4045
openURL:(NSURL *)URL
4146
sourceApplication:(NSString *)sourceApplication
@@ -56,16 +61,16 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
5661

5762
RCT_EXPORT_METHOD(openURL:(NSURL *)URL)
5863
{
64+
// Doesn't really matter what thread we call this on since it exits the app
5965
[[UIApplication sharedApplication] openURL:URL];
6066
}
6167

6268
RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
6369
callback:(RCTResponseSenderBlock)callback)
6470
{
65-
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
66-
BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:URL];
67-
callback(@[@(canOpen)]);
68-
});
71+
// This can be expensive, so we deliberately don't call on main thread
72+
BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:URL];
73+
callback(@[@(canOpen)]);
6974
}
7075

7176
- (NSDictionary *)constantsToExport

React/Base/RCTBridge.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ extern NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
6262
/**
6363
* This method is used to call functions in the JavaScript application context.
6464
* It is primarily intended for use by modules that require two-way communication
65-
* with the JavaScript code. Method should be regsitered using the
65+
* with the JavaScript code. Method should be registered using the
6666
* RCT_IMPORT_METHOD macro below. Attempting to call a method that has not been
67-
* registered will result in an error.
67+
* registered will result in an error. Safe to call from any thread.
6868
*/
6969
- (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args;
7070

@@ -112,17 +112,17 @@ static const char *__rct_import_##module##_##method##__ = #module"."#method;
112112
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
113113

114114
/**
115-
* Reload the bundle and reset executor and modules.
115+
* Reload the bundle and reset executor & modules. Safe to call from any thread.
116116
*/
117117
- (void)reload;
118118

119119
/**
120-
* Add a new observer that will be called on every screen refresh
120+
* Add a new observer that will be called on every screen refresh.
121121
*/
122122
- (void)addFrameUpdateObserver:(id<RCTFrameUpdateObserver>)observer;
123123

124124
/**
125-
* Stop receiving screen refresh updates for the given observer
125+
* Stop receiving screen refresh updates for the given observer.
126126
*/
127127
- (void)removeFrameUpdateObserver:(id<RCTFrameUpdateObserver>)observer;
128128

React/Base/RCTBridge.m

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ @implementation RCTModuleMethod
228228
NSMethodSignature *_methodSignature;
229229
NSArray *_argumentBlocks;
230230
NSString *_methodName;
231+
dispatch_block_t _methodQueue;
231232
}
232233

233234
static Class _globalExecutorClass;
@@ -762,6 +763,7 @@ @implementation RCTBridge
762763
{
763764
RCTSparseArray *_modulesByID;
764765
RCTSparseArray *_queuesByID;
766+
dispatch_queue_t _methodQueue;
765767
NSDictionary *_modulesByName;
766768
id<RCTJavaScriptExecutor> _javaScriptExecutor;
767769
Class _executorClass;
@@ -787,7 +789,6 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL
787789
[self setUp];
788790
[self bindKeys];
789791
}
790-
791792
return self;
792793
}
793794

@@ -797,6 +798,7 @@ - (void)setUp
797798
_javaScriptExecutor = RCTCreateExecutor(executorClass);
798799
_latestJSExecutor = _javaScriptExecutor;
799800
_eventDispatcher = [[RCTEventDispatcher alloc] initWithBridge:self];
801+
_methodQueue = dispatch_queue_create("com.facebook.React.BridgeMethodQueue", DISPATCH_QUEUE_SERIAL);
800802
_displayLink = [[RCTDisplayLink alloc] initWithBridge:self];
801803
_frameUpdateObservers = [[NSMutableSet alloc] init];
802804
_scheduledCalls = [[NSMutableArray alloc] init];
@@ -850,11 +852,14 @@ - (void)setUp
850852
}
851853
}
852854

853-
// Get method queue
855+
// Get method queues
854856
_queuesByID = [[RCTSparseArray alloc] init];
855857
[_modulesByID enumerateObjectsUsingBlock:^(id<RCTBridgeModule> module, NSNumber *moduleID, BOOL *stop) {
856858
if ([module respondsToSelector:@selector(methodQueue)]) {
857-
_queuesByID[moduleID] = [module methodQueue] ?: dispatch_get_main_queue();
859+
dispatch_queue_t queue = [module methodQueue];
860+
if (queue) {
861+
_queuesByID[moduleID] = queue;
862+
}
858863
}
859864
}];
860865

@@ -895,11 +900,6 @@ - (void)setUp
895900
} else {
896901
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
897902
object:self];
898-
899-
[[NSNotificationCenter defaultCenter] addObserver:self
900-
selector:@selector(reload)
901-
name:RCTReloadNotification
902-
object:nil];
903903
}
904904
[[NSNotificationCenter defaultCenter] addObserver:self
905905
selector:@selector(reload)
@@ -1205,7 +1205,7 @@ - (void)_handleBuffer:(id)buffer context:(NSNumber *)context
12051205
[_modulesByID enumerateObjectsUsingBlock:^(id<RCTBridgeModule> module, NSNumber *moduleID, BOOL *stop) {
12061206
if ([module respondsToSelector:@selector(batchDidComplete)]) {
12071207
dispatch_queue_t queue = _queuesByID[moduleID];
1208-
dispatch_async(queue ?: dispatch_get_main_queue(), ^{
1208+
dispatch_async(queue ?: _methodQueue, ^{
12091209
[module batchDidComplete];
12101210
});
12111211
}
@@ -1240,7 +1240,7 @@ - (BOOL)_handleRequestNumber:(NSUInteger)i
12401240

12411241
__weak RCTBridge *weakSelf = self;
12421242
dispatch_queue_t queue = _queuesByID[moduleID];
1243-
dispatch_async(queue ?: dispatch_get_main_queue(), ^{
1243+
dispatch_async(queue ?: _methodQueue, ^{
12441244
RCTProfileBeginEvent();
12451245
__strong RCTBridge *strongSelf = weakSelf;
12461246

@@ -1320,13 +1320,15 @@ - (void)removeFrameUpdateObserver:(id<RCTFrameUpdateObserver>)observer
13201320

13211321
- (void)reload
13221322
{
1323-
if (!_loading) {
1324-
// If the bridge has not loaded yet, the context will be already invalid at
1325-
// the time the javascript gets executed.
1326-
// It will crash the javascript, and even the next `load` won't render.
1327-
[self invalidate];
1328-
[self setUp];
1329-
}
1323+
dispatch_async(dispatch_get_main_queue(), ^{
1324+
if (!_loading) {
1325+
// If the bridge has not loaded yet, the context will be already invalid at
1326+
// the time the javascript gets executed.
1327+
// It will crash the javascript, and even the next `load` won't render.
1328+
[self invalidate];
1329+
[self setUp];
1330+
}
1331+
});
13301332
}
13311333

13321334
+ (void)logMessage:(NSString *)message level:(NSString *)level

React/Base/RCTBridgeModule.h

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,18 +91,32 @@ typedef void (^RCTResponseSenderBlock)(NSArray *response);
9191

9292
/**
9393
* The queue that will be used to call all exported methods. If omitted, this
94-
* will default the main queue, which is recommended for any methods that
95-
* interact with UIKit. If your methods perform heavy work such as filesystem
96-
* or network access, you should return a custom serial queue. Example:
94+
* will call on the default background queue, which is avoids blocking the main
95+
* thread.
96+
*
97+
* If the methods in your module need to interact with UIKit methods, they will
98+
* probably need to call those on the main thread, as most of UIKit is main-
99+
* thread-only. You can tell React Native to call your module methods on the
100+
* main thread by returning a reference to the main queue, like this:
101+
*
102+
* - (dispatch_queue_t)methodQueue
103+
* {
104+
* return dispatch_get_main_queue();
105+
* }
106+
*
107+
* If your methods perform heavy work such as synchronous filesystem or network
108+
* access, you probably don't want to block the default background queue, as
109+
* this will stall other methods. Instead, you should return a custom serial
110+
* queue, like this:
97111
*
98112
* - (dispatch_queue_t)methodQueue
99113
* {
100114
* return dispatch_queue_create("com.mydomain.FileQueue", DISPATCH_QUEUE_SERIAL);
101115
* }
102116
*
103-
* Alternatively, if only some methods on the module should be executed on a
104-
* background queue you can leave this method unimplemented, and simply
105-
* dispatch_async() within the method itself.
117+
* Alternatively, if only some methods of the module should be executed on a
118+
* particular queue you can leave this method unimplemented, and simply
119+
* dispatch_async() to the required queue within the method itself.
106120
*/
107121
- (dispatch_queue_t)methodQueue;
108122

React/Modules/RCTAlertManager.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ - (instancetype)init
3535
return self;
3636
}
3737

38+
- (dispatch_queue_t)methodQueue
39+
{
40+
return dispatch_get_main_queue();
41+
}
42+
3843
/**
3944
* @param {NSDictionary} args Dictionary of the form
4045
*

React/Modules/RCTStatusBarManager.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ static BOOL RCTViewControllerBasedStatusBarAppearance()
2626

2727
RCT_EXPORT_MODULE()
2828

29+
- (dispatch_queue_t)methodQueue
30+
{
31+
return dispatch_get_main_queue();
32+
}
33+
2934
RCT_EXPORT_METHOD(setStyle:(UIStatusBarStyle)statusBarStyle
3035
animated:(BOOL)animated)
3136
{

React/Modules/RCTTiming.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ - (void)dealloc
108108
[[NSNotificationCenter defaultCenter] removeObserver:self];
109109
}
110110

111+
- (dispatch_queue_t)methodQueue
112+
{
113+
return dispatch_get_main_queue();
114+
}
115+
111116
- (BOOL)isValid
112117
{
113118
return _bridge != nil;

0 commit comments

Comments
 (0)