From e7bd0f056bf4edca1f0529d6eed03bbaaaca586a Mon Sep 17 00:00:00 2001
From: Alex Dvornikov <advornikov@fb.com>
Date: Thu, 23 Nov 2017 04:59:23 -0800
Subject: [PATCH] Remove self capturing RCTCxxBridge->_pendingCalls

Differential Revision: D6387237

fbshipit-source-id: 3244bba439ba9fc38c5be09657cbdc787b9b4585
---
 React/CxxBridge/RCTCxxBridge.mm | 38 ++++++++++++++++++++++-----------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm
index 937c0997acefd6..202ff06f037096 100644
--- a/React/CxxBridge/RCTCxxBridge.mm
+++ b/React/CxxBridge/RCTCxxBridge.mm
@@ -61,6 +61,8 @@ @interface RCTCxxBridge : RCTBridge
 
 static NSString *const RCTJSThreadName = @"com.facebook.react.JavaScript";
 
+typedef void (^RCTPendingCall)();
+
 using namespace facebook::react;
 
 /**
@@ -157,7 +159,7 @@ @implementation RCTCxxBridge
   BOOL _wasBatchActive;
   BOOL _didInvalidate;
 
-  NSMutableArray<dispatch_block_t> *_pendingCalls;
+  NSMutableArray<RCTPendingCall> *_pendingCalls;
   std::atomic<NSInteger> _pendingCount;
 
   // Native modules
@@ -972,7 +974,7 @@ - (void)logMessage:(NSString *)message level:(NSString *)level
 
 #pragma mark - RCTBridge methods
 
-- (void)_runAfterLoad:(dispatch_block_t)block
+- (void)_runAfterLoad:(RCTPendingCall)block
 {
   // Ordering here is tricky.  Ideally, the C++ bridge would provide
   // functionality to defer calls until after the app is loaded.  Until that
@@ -1025,9 +1027,9 @@ - (void)_flushPendingCalls
   // Phase B: _flushPendingCalls happens.  Each block in _pendingCalls is
   // executed, adding work to the queue, and _pendingCount is decremented.
   // loading is set to NO.
-  NSArray *pendingCalls = _pendingCalls;
+  NSArray<RCTPendingCall> *pendingCalls = _pendingCalls;
   _pendingCalls = nil;
-  for (dispatch_block_t call in pendingCalls) {
+  for (RCTPendingCall call in pendingCalls) {
     call();
     _pendingCount--;
   }
@@ -1050,18 +1052,23 @@ - (void)enqueueJSCall:(NSString *)module method:(NSString *)method args:(NSArray
   RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueJSCall:]", nil);
 
   RCTProfileBeginFlowEvent();
-  [self _runAfterLoad:^{
+  __weak __typeof(self) weakSelf = self;
+  [self _runAfterLoad:^(){
     RCTProfileEndFlowEvent();
+    __strong __typeof(weakSelf) strongSelf = weakSelf;
+    if (!strongSelf) {
+      return;
+    }
 
-    if (self->_reactInstance) {
-      self->_reactInstance->callJSFunction([module UTF8String], [method UTF8String],
-                                           convertIdToFollyDynamic(args ?: @[]));
+    if (strongSelf->_reactInstance) {
+      strongSelf->_reactInstance->callJSFunction([module UTF8String], [method UTF8String],
+                                             convertIdToFollyDynamic(args ?: @[]));
 
       // ensureOnJavaScriptThread may execute immediately, so use jsMessageThread, to make sure
       // the block is invoked after callJSFunction
       if (completion) {
-        if (self->_jsMessageThread) {
-          self->_jsMessageThread->runOnQueue(completion);
+        if (strongSelf->_jsMessageThread) {
+          strongSelf->_jsMessageThread->runOnQueue(completion);
         } else {
           RCTLogWarn(@"Can't invoke completion without messageThread");
         }
@@ -1086,11 +1093,16 @@ - (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args
    */
 
   RCTProfileBeginFlowEvent();
-  [self _runAfterLoad:^{
+  __weak __typeof(self) weakSelf = self;
+  [self _runAfterLoad:^(){
     RCTProfileEndFlowEvent();
+    __strong __typeof(weakSelf) strongSelf = weakSelf;
+    if (!strongSelf) {
+      return;
+    }
 
-    if (self->_reactInstance) {
-      self->_reactInstance->callJSCallback([cbID unsignedLongLongValue], convertIdToFollyDynamic(args ?: @[]));
+    if (strongSelf->_reactInstance) {
+      strongSelf->_reactInstance->callJSCallback([cbID unsignedLongLongValue], convertIdToFollyDynamic(args ?: @[]));
     }
   }];
 }