Verify exported modules only once to support dynamic context in DEBUG-mode

Summary:
**Motivation:** We have a project that dynamically changes classes in runtime. This component is initialised within the React Native context. Therefor `RCTBatchedBridge` copies the classes before changes are made to them. While React Native is running, changes are made to the classes dynamically. When the project reloads the `RCTBatchedBridge`, it now has an invalid list of classes containing trash pointers. This causes the project to crash on https://github.com/facebook/react-native/blob/master/React/Base/RCTBatchedBridge.m#L288 with EXC_BAD_ACCESS in the DEBUG-mode.

**Solution:** Copy the class list on each reload to get the current state. Since this is only a DEBUG-feature the overhead of this should not be a major issue.
Closes https://github.com/facebook/react-native/pull/9541

Differential Revision: D3775012

Pulled By: javache

fbshipit-source-id: d55fa0742ca100d8018c73080230cf718aa5a7e9
This commit is contained in:
Kasper Hirvikoski 2016-08-29 12:07:28 -07:00 committed by Facebook Github Bot 1
parent 3fb76696bb
commit 101190f7f8
1 changed files with 23 additions and 23 deletions

View File

@ -266,38 +266,38 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)dele
extraModules = self.moduleProvider();
}
if (RCT_DEBUG && !RCTRunningInTestEnvironment()) {
// Check for unexported modules
static Class *classes;
static unsigned int classCount;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (RCT_DEBUG && !RCTRunningInTestEnvironment()) {
// Check for unexported modules
Class *classes;
unsigned int classCount;
classes = objc_copyClassList(&classCount);
});
NSMutableSet *moduleClasses = [NSMutableSet new];
[moduleClasses addObjectsFromArray:RCTGetModuleClasses()];
[moduleClasses addObjectsFromArray:[extraModules valueForKeyPath:@"class"]];
NSMutableSet *moduleClasses = [NSMutableSet new];
[moduleClasses addObjectsFromArray:RCTGetModuleClasses()];
[moduleClasses addObjectsFromArray:[extraModules valueForKeyPath:@"class"]];
for (unsigned int i = 0; i < classCount; i++)
{
Class cls = classes[i];
Class superclass = cls;
while (superclass)
for (unsigned int i = 0; i < classCount; i++)
{
if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule)))
Class cls = classes[i];
Class superclass = cls;
while (superclass)
{
if (![moduleClasses containsObject:cls] &&
![cls respondsToSelector:@selector(moduleName)]) {
RCTLogWarn(@"Class %@ was not exported. Did you forget to use "
"RCT_EXPORT_MODULE()?", cls);
if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule)))
{
if (![moduleClasses containsObject:cls] &&
![cls respondsToSelector:@selector(moduleName)]) {
RCTLogWarn(@"Class %@ was not exported. Did you forget to use "
"RCT_EXPORT_MODULE()?", cls);
}
break;
}
break;
superclass = class_getSuperclass(superclass);
}
superclass = class_getSuperclass(superclass);
}
}
}
});
NSMutableArray<Class> *moduleClassesByID = [NSMutableArray new];
NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray new];