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