1// Copyright © 2018 650 Industries. All rights reserved. 2 3#import <objc/runtime.h> 4 5#import <ABI48_0_0ExpoModulesCore/ABI48_0_0EXModuleRegistry.h> 6#import <ABI48_0_0ExpoModulesCore/ABI48_0_0EXModuleRegistryConsumer.h> 7 8@interface ABI48_0_0EXModuleRegistry () 9 10@property (nonatomic, weak) id<ABI48_0_0EXModuleRegistryDelegate> delegate; 11 12@property NSMutableSet<id<ABI48_0_0EXInternalModule>> *internalModulesSet; 13@property NSMapTable<Protocol *, id<ABI48_0_0EXInternalModule>> *internalModules; 14@property NSMapTable<Protocol *, NSMutableArray<id<ABI48_0_0EXInternalModule>> *> *internalModulesPreResolution; 15@property NSMapTable<Class, ABI48_0_0EXExportedModule *> *exportedModulesByClass; 16@property NSMutableDictionary<const NSString *, ABI48_0_0EXExportedModule *> *exportedModules; 17@property NSMutableDictionary<const NSString *, ABI48_0_0EXViewManager *> *viewManagerModules; 18@property NSMutableDictionary<const NSString *, id> *singletonModules; 19 20@property NSPointerArray *registryConsumers; 21 22@end 23 24@implementation ABI48_0_0EXModuleRegistry 25 26# pragma mark - Lifecycle 27 28- (instancetype)init 29{ 30 if (self = [super init]) { 31 _internalModulesPreResolution = [NSMapTable weakToStrongObjectsMapTable]; 32 _exportedModulesByClass = [NSMapTable weakToWeakObjectsMapTable]; 33 _exportedModules = [NSMutableDictionary dictionary]; 34 _viewManagerModules = [NSMutableDictionary dictionary]; 35 _singletonModules = [NSMutableDictionary dictionary]; 36 _registryConsumers = [NSPointerArray weakObjectsPointerArray]; 37 } 38 return self; 39} 40 41- (instancetype)initWithInternalModules:(NSSet<id<ABI48_0_0EXInternalModule>> *)internalModules 42 exportedModules:(NSSet<ABI48_0_0EXExportedModule *> *)exportedModules 43 viewManagers:(NSSet<ABI48_0_0EXViewManager *> *)viewManagers 44 singletonModules:(NSSet *)singletonModules 45{ 46 if (self = [self init]) { 47 for (id<ABI48_0_0EXInternalModule> internalModule in internalModules) { 48 [self registerInternalModule:internalModule]; 49 } 50 51 for (ABI48_0_0EXExportedModule *exportedModule in exportedModules) { 52 [self registerExportedModule:exportedModule]; 53 } 54 55 for (ABI48_0_0EXViewManager *viewManager in viewManagers) { 56 [self registerViewManager:viewManager]; 57 } 58 59 for (id singletonModule in singletonModules) { 60 [self registerSingletonModule:singletonModule]; 61 } 62 } 63 return self; 64} 65 66- (void)setDelegate:(id<ABI48_0_0EXModuleRegistryDelegate>)delegate 67{ 68 _delegate = delegate; 69} 70 71// Fills in _internalModules and _internalModulesSet 72- (void)resolveInternalModulesConflicts 73{ 74 if (_internalModules) { 75 // Conflict resolution has already been completed. 76 return; 77 } 78 79 _internalModules = [NSMapTable weakToStrongObjectsMapTable]; 80 _internalModulesSet = [NSMutableSet new]; 81 for (Protocol *protocol in _internalModulesPreResolution) { 82 NSArray<id<ABI48_0_0EXInternalModule>> *conflictingModules = [_internalModulesPreResolution objectForKey:protocol]; 83 84 id<ABI48_0_0EXInternalModule> resolvedModule; 85 if ([conflictingModules count] > 1 && _delegate) { 86 resolvedModule = [_delegate pickInternalModuleImplementingInterface:protocol fromAmongModules:conflictingModules]; 87 } else { 88 resolvedModule = [conflictingModules lastObject]; 89 } 90 91 [_internalModules setObject:resolvedModule forKey:protocol]; 92 [self maybeAddRegistryConsumer:resolvedModule]; 93 [_internalModulesSet addObject:resolvedModule]; 94 } 95 96 _internalModulesPreResolution = nil; // Remove references to discarded modules 97} 98 99- (void)initialize 100{ 101 [self resolveInternalModulesConflicts]; 102 for (id<ABI48_0_0EXModuleRegistryConsumer> registryConsumer in _registryConsumers) { 103 [registryConsumer setModuleRegistry:self]; 104 } 105} 106 107# pragma mark - Registering modules 108 109- (void)registerInternalModule:(id<ABI48_0_0EXInternalModule>)internalModule 110{ 111 for (Protocol *exportedInterface in [[internalModule class] exportedInterfaces]) { 112 if (_internalModules) { 113 id<ABI48_0_0EXInternalModule> resolvedModule = internalModule; 114 if (_delegate && [_internalModules objectForKey:exportedInterface]) { 115 id<ABI48_0_0EXInternalModule> oldModule = [_internalModules objectForKey:exportedInterface]; 116 resolvedModule = [_delegate pickInternalModuleImplementingInterface:exportedInterface fromAmongModules:@[oldModule, internalModule]]; 117 } 118 [_internalModules setObject:resolvedModule forKey:exportedInterface]; 119 [self maybeAddRegistryConsumer:resolvedModule]; 120 [_internalModulesSet addObject:resolvedModule]; 121 } else { 122 if (![_internalModulesPreResolution objectForKey:exportedInterface]) { 123 [_internalModulesPreResolution setObject:[NSMutableArray array] forKey:exportedInterface]; 124 } 125 126 [[_internalModulesPreResolution objectForKey:exportedInterface] addObject:internalModule]; 127 } 128 } 129} 130 131- (void)registerExportedModule:(ABI48_0_0EXExportedModule *)exportedModule 132{ 133 const NSString *exportedModuleName = [[exportedModule class] exportedModuleName]; 134 if (_exportedModules[exportedModuleName]) { 135 ABI48_0_0EXLogInfo(@"Module %@ overrides %@ as the module exported as %@.", exportedModule, _exportedModules[exportedModuleName], exportedModuleName); 136 } 137 138 _exportedModules[exportedModuleName] = exportedModule; 139 [_exportedModulesByClass setObject:exportedModule forKey:[exportedModule class]]; 140 [self maybeAddRegistryConsumer:exportedModule]; 141} 142 143- (void)registerViewManager:(ABI48_0_0EXViewManager *)viewManager 144{ 145 const NSString *exportedModuleName = [[viewManager class] exportedModuleName]; 146 if (_viewManagerModules[exportedModuleName]) { 147 ABI48_0_0EXLogInfo(@"View manager %@ overrides %@ as the module exported as %@.", viewManager, _viewManagerModules[exportedModuleName], exportedModuleName); 148 } 149 150 _viewManagerModules[exportedModuleName] = viewManager; 151 [self maybeAddRegistryConsumer:viewManager]; 152} 153 154- (void)registerSingletonModule:(id)singletonModule 155{ 156 if ([[singletonModule class] respondsToSelector:@selector(name)]) { 157 #pragma clang diagnostic push 158 #pragma clang diagnostic ignored "-Wobjc-method-access" 159 [_singletonModules setObject:singletonModule forKey:[[singletonModule class] name]]; 160 #pragma clang diagnostic pop 161 } else { 162 ABI48_0_0EXLogWarn(@"One of the singleton modules does not respond to +(NSString *)name selector. This probably means you're either try to pass a strange object as a singleton module (it won't get registered in the module registry, sorry) or the ABI48_0_0EXSingletonModule interface and the ABI48_0_0EXModuleRegistry implementations versions are out of sync, which means things will probably not work as expected."); 163 } 164} 165 166- (void)maybeAddRegistryConsumer:(id)maybeConsumer 167{ 168 if ([maybeConsumer conformsToProtocol:@protocol(ABI48_0_0EXModuleRegistryConsumer)]) { 169 [self addRegistryConsumer:(id<ABI48_0_0EXModuleRegistryConsumer>)maybeConsumer]; 170 } 171} 172 173- (void)addRegistryConsumer:(id<ABI48_0_0EXModuleRegistryConsumer>)registryConsumer 174{ 175 void *ptr = (__bridge void * _Nullable)registryConsumer; 176 177 for (id consumerPtr in _registryConsumers) { 178 if (consumerPtr == ptr) { 179 return; 180 } 181 } 182 [_registryConsumers addPointer:ptr]; 183} 184 185# pragma mark - Registry API 186 187- (id)getModuleImplementingProtocol:(Protocol *)protocol 188{ 189 [self resolveInternalModulesConflicts]; 190 return [_internalModules objectForKey:protocol]; 191} 192 193- (ABI48_0_0EXExportedModule *)getExportedModuleForName:(NSString *)name 194{ 195 return _exportedModules[name]; 196} 197 198- (ABI48_0_0EXExportedModule *)getExportedModuleOfClass:(Class)moduleClass 199{ 200 return [_exportedModulesByClass objectForKey:moduleClass]; 201} 202 203- (id)getSingletonModuleForName:(NSString *)singletonModuleName 204{ 205 return [_singletonModules objectForKey:singletonModuleName]; 206} 207 208- (NSArray<id<ABI48_0_0EXInternalModule>> *)getAllInternalModules 209{ 210 [self resolveInternalModulesConflicts]; 211 return [_internalModulesSet allObjects]; 212} 213 214- (NSArray<ABI48_0_0EXExportedModule *> *)getAllExportedModules 215{ 216 return [_exportedModules allValues]; 217} 218 219- (NSArray<ABI48_0_0EXViewManager *> *)getAllViewManagers 220{ 221 return [_viewManagerModules allValues]; 222} 223 224- (NSArray *)getAllSingletonModules 225{ 226 return [_singletonModules allValues]; 227} 228 229@end 230