@@ -62,31 +62,6 @@ static void RCTAppendError(NSDictionary *error, NSMutableArray<NSDictionary *> *
6262 return nil ;
6363}
6464
65- static NSString *RCTGetStorageDirectory ()
66- {
67- static NSString *storageDirectory = nil ;
68- static dispatch_once_t onceToken;
69- dispatch_once (&onceToken, ^{
70- #if TARGET_OS_TV
71- storageDirectory = NSSearchPathForDirectoriesInDomains (NSCachesDirectory, NSUserDomainMask, YES ).firstObject ;
72- #else
73- storageDirectory = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES ).firstObject ;
74- #endif
75- storageDirectory = [storageDirectory stringByAppendingPathComponent: RCTStorageDirectory];
76- });
77- return storageDirectory;
78- }
79-
80- static NSString *RCTGetManifestFilePath ()
81- {
82- static NSString *manifestFilePath = nil ;
83- static dispatch_once_t onceToken;
84- dispatch_once (&onceToken, ^{
85- manifestFilePath = [RCTGetStorageDirectory () stringByAppendingPathComponent: RCTManifestFileName];
86- });
87- return manifestFilePath;
88- }
89-
9065// Only merges objects - all other types are just clobbered (including arrays)
9166static BOOL RCTMergeRecursive (NSMutableDictionary *destination, NSDictionary *source)
9267{
@@ -115,73 +90,78 @@ static BOOL RCTMergeRecursive(NSMutableDictionary *destination, NSDictionary *so
11590 return modified;
11691}
11792
118- static dispatch_queue_t RCTGetMethodQueue ()
119- {
120- // We want all instances to share the same queue since they will be reading/writing the same files.
121- static dispatch_queue_t queue;
122- static dispatch_once_t onceToken;
123- dispatch_once (&onceToken, ^{
124- queue = dispatch_queue_create (" com.facebook.react.AsyncLocalStorageQueue" , DISPATCH_QUEUE_SERIAL);
125- });
126- return queue;
127- }
93+ // NOTE(nikki93): We replace with scoped implementations of:
94+ // RCTGetStorageDirectory()
95+ // RCTGetManifestFilePath()
96+ // RCTGetMethodQueue()
97+ // RCTGetCache()
98+ // RCTDeleteStorageDirectory()
12899
129- static NSCache *RCTGetCache ()
130- {
131- // We want all instances to share the same cache since they will be reading/writing the same files.
132- static NSCache *cache;
133- static dispatch_once_t onceToken;
134- dispatch_once (&onceToken, ^{
135- cache = [NSCache new ];
136- cache.totalCostLimit = 2 * 1024 * 1024 ; // 2MB
137-
138- // Clear cache in the event of a memory warning
139- [[NSNotificationCenter defaultCenter ] addObserverForName: UIApplicationDidReceiveMemoryWarningNotification object: nil queue: nil usingBlock: ^(__unused NSNotification *note) {
140- [cache removeAllObjects ];
141- }];
142- });
143- return cache;
144- }
100+ #define RCTGetStorageDirectory () _storageDirectory
101+ #define RCTGetManifestFilePath () _manifestFilePath
102+ #define RCTGetMethodQueue () self.methodQueue
103+ #define RCTGetCache () self.cache
145104
146- static BOOL RCTHasCreatedStorageDirectory = NO ;
147- static NSDictionary *RCTDeleteStorageDirectory ()
105+ static NSDictionary *RCTDeleteStorageDirectory (NSString *storageDirectory)
148106{
149107 NSError *error;
150- [[NSFileManager defaultManager ] removeItemAtPath: RCTGetStorageDirectory () error: &error];
151- RCTHasCreatedStorageDirectory = NO ;
108+ [[NSFileManager defaultManager ] removeItemAtPath: storageDirectory error: &error];
152109 return error ? RCTMakeError (@" Failed to delete storage directory." , error, nil ) : nil ;
153110}
111+ #define RCTDeleteStorageDirectory () RCTDeleteStorageDirectory(_storageDirectory)
154112
155113#pragma mark - RCTAsyncLocalStorage
156114
115+ @interface RCTAsyncLocalStorage ()
116+
117+ @property (nonatomic , copy ) NSString *storageDirectory;
118+ @property (nonatomic , copy ) NSString *manifestFilePath;
119+
120+ @end
121+
157122@implementation RCTAsyncLocalStorage
158123{
159124 BOOL _haveSetup;
160125 // The manifest is a dictionary of all keys with small values inlined. Null values indicate values that are stored
161126 // in separate files (as opposed to nil values which don't exist). The manifest is read off disk at startup, and
162127 // written to disk after all mutations.
163128 NSMutableDictionary <NSString *, NSString *> *_manifest;
129+ NSCache *_cache;
130+ dispatch_once_t *_cacheOnceToken;
164131}
165132
166- RCT_EXPORT_MODULE ()
167-
168- - (dispatch_queue_t )methodQueue
133+ // NOTE(nikki93): Prevents the module from being auto-initialized and allows us to pass our own `storageDirectory`
134+ + ( NSString *) moduleName { return @" RCTAsyncLocalStorage " ; }
135+ - (instancetype ) initWithStorageDirectory : ( NSString *) storageDirectory
169136{
170- return RCTGetMethodQueue ();
137+ if ((self = [super init ])) {
138+ _storageDirectory = storageDirectory;
139+ _manifestFilePath = [RCTGetStorageDirectory () stringByAppendingPathComponent: RCTManifestFileName];
140+ }
141+ return self;
171142}
172143
173- - (void )clearAllData
144+ // NOTE(nikki93): Use the default `methodQueue` since instances have different storage directories
145+ @synthesize methodQueue = _methodQueue;
146+
147+ - (NSCache *)cache
174148{
175- dispatch_async (RCTGetMethodQueue (), ^{
176- [self ->_manifest removeAllObjects ];
177- [RCTGetCache () removeAllObjects ];
178- RCTDeleteStorageDirectory ();
149+ dispatch_once (&_cacheOnceToken, ^{
150+ _cache = [NSCache new ];
151+ _cache.totalCostLimit = 2 * 1024 * 1024 ; // 2MB
152+
153+ // Clear cache in the event of a memory warning
154+ [[NSNotificationCenter defaultCenter ] addObserverForName: UIApplicationDidReceiveMemoryWarningNotification object: nil queue: nil usingBlock: ^(__unused NSNotification *note) {
155+ [_cache removeAllObjects ];
156+ }];
179157 });
158+ return _cache;
180159}
181160
182- + (void )clearAllData
161+ - (void )clearAllData
183162{
184163 dispatch_async (RCTGetMethodQueue (), ^{
164+ [self ->_manifest removeAllObjects ];
185165 [RCTGetCache () removeAllObjects ];
186166 RCTDeleteStorageDirectory ();
187167 });
@@ -223,15 +203,13 @@ - (NSDictionary *)_ensureSetup
223203#endif
224204
225205 NSError *error = nil ;
226- if (!RCTHasCreatedStorageDirectory) {
227- [[NSFileManager defaultManager ] createDirectoryAtPath: RCTGetStorageDirectory ()
228- withIntermediateDirectories: YES
229- attributes: nil
230- error: &error];
231- if (error) {
232- return RCTMakeError (@" Failed to create storage directory." , error, nil );
233- }
234- RCTHasCreatedStorageDirectory = YES ;
206+ // NOTE(nikki93): `withIntermediateDirectories:YES` makes this idempotent
207+ [[NSFileManager defaultManager ] createDirectoryAtPath: RCTGetStorageDirectory ()
208+ withIntermediateDirectories: YES
209+ attributes: nil
210+ error: &error];
211+ if (error) {
212+ return RCTMakeError (@" Failed to create storage directory." , error, nil );
235213 }
236214 if (!_haveSetup) {
237215 NSDictionary *errorOut;
0 commit comments