1// Copyright © 2018 650 Industries. All rights reserved. 2 3#import <Foundation/Foundation.h> 4#import <ExpoModulesCore/EXSingletonModule.h> 5#import <ExpoModulesCore/EXModuleRegistryProvider.h> 6 7static dispatch_once_t onceToken; 8static NSMutableSet<Class> *EXModuleClasses; 9static NSMutableSet<Class> *EXSingletonModuleClasses; 10 11void (^EXinitializeGlobalModulesRegistry)(void) = ^{ 12 EXModuleClasses = [NSMutableSet set]; 13 EXSingletonModuleClasses = [NSMutableSet set]; 14}; 15 16extern void EXRegisterModule(Class); 17extern void EXRegisterModule(Class moduleClass) 18{ 19 dispatch_once(&onceToken, EXinitializeGlobalModulesRegistry); 20 [EXModuleClasses addObject:moduleClass]; 21} 22 23extern void EXRegisterSingletonModule(Class); 24extern void EXRegisterSingletonModule(Class singletonModuleClass) 25{ 26 dispatch_once(&onceToken, EXinitializeGlobalModulesRegistry); 27 28 // A heuristic solution to "multiple singletons registering 29 // to the same name" problem. Usually it happens when we want to 30 // override module singleton with an ExpoKit one. This solution 31 // gives preference to subclasses. 32 33 // If a superclass of a registering singleton is already registered 34 // we want to remove it in favor of the registering singleton. 35 Class superClass = [singletonModuleClass superclass]; 36 while (superClass != [NSObject class]) { 37 [EXSingletonModuleClasses removeObject:superClass]; 38 superClass = [superClass superclass]; 39 } 40 41 // If a registering singleton is a superclass of an already registered 42 // singleton, we don't register it. 43 for (Class registeredClass in EXSingletonModuleClasses) { 44 if ([singletonModuleClass isSubclassOfClass:registeredClass]) { 45 return; 46 } 47 } 48 49 [EXSingletonModuleClasses addObject:singletonModuleClass]; 50} 51 52// Singleton modules classes register in EXSingletonModuleClasses 53// with EXRegisterSingletonModule function. Then they should be 54// initialized exactly once (onceSingletonModulesToken guards that). 55 56static dispatch_once_t onceSingletonModulesToken; 57static NSMutableSet<EXSingletonModule *> *EXSingletonModules; 58void (^EXinitializeGlobalSingletonModulesSet)(void) = ^{ 59 EXSingletonModules = [NSMutableSet set]; 60 for (Class singletonModuleClass in EXSingletonModuleClasses) { 61 [EXSingletonModules addObject:[[singletonModuleClass alloc] init]]; 62 } 63}; 64 65@interface EXModuleRegistryProvider () 66 67@property (nonatomic, strong) NSSet *singletonModules; 68 69@end 70 71@implementation EXModuleRegistryProvider 72 73- (instancetype)init 74{ 75 return [self initWithSingletonModules:[EXModuleRegistryProvider singletonModules]]; 76} 77 78- (instancetype)initWithSingletonModules:(NSSet *)modules 79{ 80 if (self = [super init]) { 81 _singletonModules = [NSSet setWithSet:modules]; 82 } 83 return self; 84} 85 86+ (NSSet<Class> *)getModulesClasses 87{ 88 return EXModuleClasses; 89} 90 91+ (NSSet<EXSingletonModule *> *)singletonModules 92{ 93 dispatch_once(&onceSingletonModulesToken, EXinitializeGlobalSingletonModulesSet); 94 return EXSingletonModules; 95} 96 97+ (nullable EXSingletonModule *)getSingletonModuleForClass:(Class)singletonClass 98{ 99 NSSet<EXSingletonModule *> *singletonModules = [self singletonModules]; 100 101 for (EXSingletonModule *singleton in singletonModules) { 102 if ([singleton isKindOfClass:singletonClass]) { 103 return singleton; 104 } 105 } 106 return nil; 107} 108 109- (EXModuleRegistry *)moduleRegistry 110{ 111 NSMutableSet<id<EXInternalModule>> *internalModules = [NSMutableSet set]; 112 NSMutableSet<EXExportedModule *> *exportedModules = [NSMutableSet set]; 113 114 for (Class klass in [self.class getModulesClasses]) { 115 if (![klass conformsToProtocol:@protocol(EXInternalModule)]) { 116 EXLogWarn(@"Registered class `%@` does not conform to the `EXInternalModule` protocol.", [klass description]); 117 continue; 118 } 119 120 id<EXInternalModule> instance = [self createModuleInstance:klass]; 121 122 if ([[instance class] exportedInterfaces] != nil && [[[instance class] exportedInterfaces] count] > 0) { 123 [internalModules addObject:instance]; 124 } 125 126 if ([instance isKindOfClass:[EXExportedModule class]]) { 127 [exportedModules addObject:(EXExportedModule *)instance]; 128 } 129 } 130 131 EXModuleRegistry *moduleRegistry = [[EXModuleRegistry alloc] initWithInternalModules:internalModules 132 exportedModules:exportedModules 133 singletonModules:_singletonModules]; 134 [moduleRegistry setDelegate:_moduleRegistryDelegate]; 135 return moduleRegistry; 136} 137 138# pragma mark - Utilities 139 140- (id<EXInternalModule>)createModuleInstance:(Class)moduleClass 141{ 142 return [[moduleClass alloc] init]; 143} 144 145@end 146