diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/js/AsyncStorageTest.js b/Examples/UIExplorer/UIExplorerIntegrationTests/js/AsyncStorageTest.js index c440d10cd..dd7de2d69 100644 --- a/Examples/UIExplorer/UIExplorerIntegrationTests/js/AsyncStorageTest.js +++ b/Examples/UIExplorer/UIExplorerIntegrationTests/js/AsyncStorageTest.js @@ -54,6 +54,9 @@ function expectEqual(lhs, rhs, testname) { } function expectAsyncNoError(place, err) { + if (err instanceof Error) { + err = err.message; + } expectTrue(err === null, 'Unexpected error in ' + place + ': ' + JSON.stringify(err)); } diff --git a/React/Modules/RCTAsyncLocalStorage.m b/React/Modules/RCTAsyncLocalStorage.m index 50b5312f9..8300cc869 100644 --- a/React/Modules/RCTAsyncLocalStorage.m +++ b/React/Modules/RCTAsyncLocalStorage.m @@ -17,9 +17,9 @@ #import "RCTLog.h" #import "RCTUtils.h" -static NSString *const kStorageDir = @"RCTAsyncLocalStorage_V1"; -static NSString *const kManifestFilename = @"manifest.json"; -static const NSUInteger kInlineValueThreshold = 100; +static NSString *const RCTStorageDirectory = @"RCTAsyncLocalStorage_V1"; +static NSString *const RCTManifestFileName = @"manifest.json"; +static const NSUInteger RCTInlineValueThreshold = 100; #pragma mark - Static helper functions @@ -61,11 +61,25 @@ static id RCTReadFile(NSString *filePath, NSString *key, NSDictionary **errorOut return nil; } -static NSString *RCTGetStorageDir() +static NSString *RCTGetStorageDirectory() { - NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; - NSURL *homeURL = [NSURL fileURLWithPath:documentDirectory isDirectory:YES]; - return [[homeURL URLByAppendingPathComponent:kStorageDir isDirectory:YES] path]; + static NSString *storageDirectory = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + storageDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; + storageDirectory = [storageDirectory stringByAppendingPathComponent:RCTStorageDirectory]; + }); + return storageDirectory; +} + +static NSString *RCTGetManifestFilePath() +{ + static NSString *manifestFilePath = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + manifestFilePath = [RCTGetStorageDirectory() stringByAppendingPathComponent:RCTManifestFileName]; + }); + return manifestFilePath; } // Only merges objects - all other types are just clobbered (including arrays) @@ -111,7 +125,7 @@ static BOOL RCTHasCreatedStorageDirectory = NO; static NSError *RCTDeleteStorageDirectory() { NSError *error; - [[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDir() error:&error]; + [[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDirectory() error:&error]; RCTHasCreatedStorageDirectory = NO; return error; } @@ -125,8 +139,6 @@ static NSError *RCTDeleteStorageDirectory() // in separate files (as opposed to nil values which don't exist). The manifest is read off disk at startup, and // written to disk after all mutations. NSMutableDictionary *_manifest; - NSString *_manifestPath; - NSString *_storageDirectory; } RCT_EXPORT_MODULE() @@ -165,7 +177,7 @@ RCT_EXPORT_MODULE() - (NSString *)_filePathForKey:(NSString *)key { NSString *safeFileName = RCTMD5Hash(key); - return [_storageDirectory stringByAppendingPathComponent:safeFileName]; + return [RCTGetStorageDirectory() stringByAppendingPathComponent:safeFileName]; } - (id)_ensureSetup @@ -174,8 +186,7 @@ RCT_EXPORT_MODULE() NSError *error = nil; if (!RCTHasCreatedStorageDirectory) { - _storageDirectory = RCTGetStorageDir(); - [[NSFileManager defaultManager] createDirectoryAtPath:_storageDirectory + [[NSFileManager defaultManager] createDirectoryAtPath:RCTGetStorageDirectory() withIntermediateDirectories:YES attributes:nil error:&error]; @@ -185,9 +196,8 @@ RCT_EXPORT_MODULE() RCTHasCreatedStorageDirectory = YES; } if (!_haveSetup) { - _manifestPath = [_storageDirectory stringByAppendingPathComponent:kManifestFilename]; NSDictionary *errorOut; - NSString *serialized = RCTReadFile(_manifestPath, nil, &errorOut); + NSString *serialized = RCTReadFile(RCTGetManifestFilePath(), nil, &errorOut); _manifest = serialized ? [RCTJSONParse(serialized, &error) mutableCopy] : [[NSMutableDictionary alloc] init]; if (error) { RCTLogWarn(@"Failed to parse manifest - creating new one.\n\n%@", error); @@ -202,7 +212,7 @@ RCT_EXPORT_MODULE() { NSError *error; NSString *serialized = RCTJSONStringify(_manifest, &error); - [serialized writeToFile:_manifestPath atomically:YES encoding:NSUTF8StringEncoding error:&error]; + [serialized writeToFile:RCTGetManifestFilePath() atomically:YES encoding:NSUTF8StringEncoding error:&error]; id errorOut; if (error) { errorOut = RCTMakeError(@"Failed to write manifest file.", error, nil); @@ -248,7 +258,7 @@ RCT_EXPORT_MODULE() NSString *value = entry[1]; NSString *filePath = [self _filePathForKey:key]; NSError *error; - if (value.length <= kInlineValueThreshold) { + if (value.length <= RCTInlineValueThreshold) { if (_manifest[key] && _manifest[key] != (id)kCFNull) { // If the value already existed but wasn't inlined, remove the old file. [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];