From 497eb578ab32614744a4ef61d7a6bca0d4251885 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Fri, 23 Apr 2021 15:57:58 -0700 Subject: [PATCH] Fix invalidation for modules with infra-generated method queues Summary: When invalidating TurboModules, the TurboModule infra looks for a methodQueue method on the TurboModule (line 871 below). If it finds one, the TurboModuleManager dispatches module invalidate on that method queue: https://www.internalfb.com/code/fbsource/[c91dc16f4b63abd05c7c9a038e88ca692a453c69]/xplat/js/react-native-github/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm?lines=847-848%2C870-883 ## The Problem TurboModules that neither provide a method queue, nor request a method queue won't respond to selector(methodQueue). For those modules, the TurboModule system won't dispatch invalidate to their method queue ## The Fix Calling selector(methodQueue) is an unreliable way of getting the module's method queue. The TurboModuleManager attaches a method queue to every TurboModule as an associated object: https://www.internalfb.com/code/fbsource/[c91dc16f4b63]/xplat/js/react-native-github/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm?lines=636 In this diff, in the TurboModule invalidate method, we retrieve the method queue using ObjC's associated object API. This guarantees that all TurboModules will be invalidated on their method queues. Changelog: [iOS][Fixed] - Invalidate TurboModules with infra-generated method queues on their method queues Reviewed By: appden Differential Revision: D27954644 fbshipit-source-id: af4408e444d03a15d8d8e154b3980511b81d5fb1 --- .../platform/ios/RCTTurboModuleManager.mm | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm b/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm index b43a4512b315e5..cd373ef7144ded 100644 --- a/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm +++ b/ReactCommon/react/nativemodule/core/platform/ios/RCTTurboModuleManager.mm @@ -884,31 +884,31 @@ - (void)_invalidateModules shouldPerfLog:NO]; if ([module respondsToSelector:@selector(invalidate)]) { - if ([module respondsToSelector:@selector(methodQueue)]) { - dispatch_queue_t methodQueue = [module performSelector:@selector(methodQueue)]; - - if (methodQueue) { - dispatch_group_enter(moduleInvalidationGroup); - dispatch_block_t invalidateModule = ^{ - [((id)module) invalidate]; - dispatch_group_leave(moduleInvalidationGroup); - }; - - if (_bridge) { - [_bridge dispatchBlock:invalidateModule queue:methodQueue]; - } else { - // Bridgeless mode - if (methodQueue == RCTJSThread) { - invalidateModule(); - } else { - dispatch_async(methodQueue, invalidateModule); - } - } - continue; - } + dispatch_queue_t methodQueue = (dispatch_queue_t)objc_getAssociatedObject(module, &kAssociatedMethodQueueKey); + + if (methodQueue == nil) { + RCTLogError( + @"TurboModuleManager: Couldn't invalidate TurboModule \"%@\", because its method queue is nil.", + [module class]); + continue; } - [((id)module) invalidate]; + dispatch_group_enter(moduleInvalidationGroup); + dispatch_block_t invalidateModule = ^{ + [((id)module) invalidate]; + dispatch_group_leave(moduleInvalidationGroup); + }; + + if (_bridge) { + [_bridge dispatchBlock:invalidateModule queue:methodQueue]; + } else { + // Bridgeless mode + if (methodQueue == RCTJSThread) { + invalidateModule(); + } else { + dispatch_async(methodQueue, invalidateModule); + } + } } }