From 2b3a4bd27d875b3fb7a0af1651488c7da5df48ca Mon Sep 17 00:00:00 2001 From: Ted Suzman Date: Tue, 1 Sep 2015 02:18:14 -0700 Subject: [PATCH] [ReactNative] Maintain order of bridge calls Summary: When bridge calls are made, they should be dispatched to their destination GCD queue in the same order they were made. (It looks like this invariant broke in 336e18d, which caused call order to depend on the iteration of `NSMapTable` keys whenever there are calls to multiple modules that share a queue) Fixes #1941 (in which RCTUIManager createView addUIBlock blocks were sometimes running after other blocks that depended on them) I'm a react-native/iOS/objc newbie, so please excuse any ignorance this commit may well contain :) Closes https://github.com/facebook/react-native/pull/2488 Github Author: Ted Suzman --- React/Base/RCTBatchedBridge.m | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index 5ef4c6502..3151d8005 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -664,22 +664,23 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR // verify that class has been registered (void)_modulesByName[moduleData.name]; } - NSMutableOrderedSet *set = [buckets objectForKey:moduleData]; + id queue = [moduleData queue]; + NSMutableOrderedSet *set = [buckets objectForKey:queue]; if (!set) { set = [NSMutableOrderedSet new]; - [buckets setObject:set forKey:moduleData]; + [buckets setObject:set forKey:queue]; } [set addObject:@(i)]; } - for (RCTModuleData *moduleData in buckets) { + for (id queue in buckets) { RCTProfileBeginFlowEvent(); - [moduleData dispatchBlock:^{ + dispatch_block_t block = ^{ RCTProfileEndFlowEvent(); RCTProfileBeginEvent(0, RCTCurrentThreadName(), nil); - NSOrderedSet *calls = [buckets objectForKey:moduleData]; + NSOrderedSet *calls = [buckets objectForKey:queue]; @autoreleasepool { for (NSNumber *indexObj in calls) { NSUInteger index = indexObj.unsignedIntegerValue; @@ -693,7 +694,13 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR RCTProfileEndEvent(0, @"objc_call,dispatch_async", @{ @"calls": @(calls.count), }); - }]; + }; + + if (queue == RCTJSThread) { + [_javaScriptExecutor executeBlockOnJavaScriptQueue:block]; + } else if (queue) { + dispatch_async(queue, block); + } } // TODO: batchDidComplete is only used by RCTUIManager - can we eliminate this special case?