Skip to content

Commit 7e36847

Browse files
committed
iOS: Allow brownfield apps to handle storage.
1 parent 566bbb2 commit 7e36847

File tree

4 files changed

+167
-12
lines changed

4 files changed

+167
-12
lines changed

ios/RNCAsyncStorage.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#import <React/RCTBridgeModule.h>
99
#import <React/RCTInvalidating.h>
10+
#import <RNCAsyncStorage/RNCAsyncStorageDelegate.h>
1011

1112
/**
1213
* A simple, asynchronous, persistent, key-value storage system designed as a
@@ -21,6 +22,8 @@
2122
*/
2223
@interface RNCAsyncStorage : NSObject <RCTBridgeModule,RCTInvalidating>
2324

25+
@property (nonatomic, weak, nullable) id<RNCAsyncStorageDelegate> delegate;
26+
2427
@property (nonatomic, assign) BOOL clearOnInvalidate;
2528

2629
@property (nonatomic, readonly, getter=isValid) BOOL valid;
@@ -37,5 +40,4 @@
3740
// Add multiple key value pairs to the cache.
3841
- (void)multiSet:(NSArray<NSArray<NSString *> *> *)kvPairs callback:(RCTResponseSenderBlock)callback;
3942

40-
4143
@end

ios/RNCAsyncStorage.m

Lines changed: 109 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ static void RCTAppendError(NSDictionary *error, NSMutableArray<NSDictionary *> *
4343
}
4444
}
4545

46+
static NSArray<NSDictionary *> *RCTMakeErrors(NSArray<id<NSObject>> *results) {
47+
NSMutableArray<NSDictionary *> *errors;
48+
for (id object in results) {
49+
if ([object isKindOfClass:[NSError class]]) {
50+
NSError *error = (NSError *)object;
51+
NSDictionary *keyError = RCTMakeError(error.localizedDescription, error, nil);
52+
RCTAppendError(keyError, &errors);
53+
}
54+
}
55+
return errors;
56+
}
57+
4658
static NSString *RCTReadFile(NSString *filePath, NSString *key, NSDictionary **errorOut)
4759
{
4860
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
@@ -329,30 +341,77 @@ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL
329341
return errorOut;
330342
}
331343

344+
- (void)_multiGet:(NSArray<NSString *> *)keys
345+
callback:(RCTResponseSenderBlock)callback
346+
getter:(NSString *(^)(NSUInteger i, NSString *key, NSDictionary **errorOut))getValue
347+
{
348+
NSMutableArray<NSDictionary *> *errors;
349+
NSMutableArray<NSArray<NSString *> *> *result = [NSMutableArray arrayWithCapacity:keys.count];
350+
for (NSUInteger i = 0; i < keys.count; ++i) {
351+
NSString *key = keys[i];
352+
id keyError;
353+
id value = getValue(i, key, &keyError);
354+
[result addObject:@[key, RCTNullIfNil(value)]];
355+
RCTAppendError(keyError, &errors);
356+
}
357+
callback(@[RCTNullIfNil(errors), result]);
358+
}
359+
332360
#pragma mark - Exported JS Functions
333361

334362
RCT_EXPORT_METHOD(multiGet:(NSArray<NSString *> *)keys
335363
callback:(RCTResponseSenderBlock)callback)
336364
{
365+
if (self.delegate != nil) {
366+
[self.delegate valuesForKeys:keys completion:^(NSArray<id<NSObject>> *valuesOrErrors) {
367+
[self _multiGet:keys
368+
callback:callback
369+
getter:^NSString *(NSUInteger i, NSString *key, NSDictionary **errorOut) {
370+
id valueOrError = valuesOrErrors[i];
371+
if ([valueOrError isKindOfClass:[NSError class]]) {
372+
NSError *error = (NSError *)valueOrError;
373+
NSDictionary *extraData = @{@"key": RCTNullIfNil(key)};
374+
*errorOut = RCTMakeError(error.localizedDescription, error, extraData);
375+
return nil;
376+
} else {
377+
return [valueOrError isKindOfClass:[NSString class]]
378+
? (NSString *)valueOrError
379+
: nil;
380+
}
381+
}];
382+
}];
383+
return;
384+
}
385+
337386
NSDictionary *errorOut = [self _ensureSetup];
338387
if (errorOut) {
339388
callback(@[@[errorOut], (id)kCFNull]);
340389
return;
341390
}
342-
NSMutableArray<NSDictionary *> *errors;
343-
NSMutableArray<NSArray<NSString *> *> *result = [[NSMutableArray alloc] initWithCapacity:keys.count];
344-
for (NSString *key in keys) {
345-
id keyError;
346-
id value = [self _getValueForKey:key errorOut:&keyError];
347-
[result addObject:@[key, RCTNullIfNil(value)]];
348-
RCTAppendError(keyError, &errors);
349-
}
350-
callback(@[RCTNullIfNil(errors), result]);
391+
[self _multiGet:keys
392+
callback:callback
393+
getter:^(NSUInteger i, NSString *key, NSDictionary **errorOut) {
394+
return [self _getValueForKey:key errorOut:errorOut];
395+
}];
351396
}
352397

353398
RCT_EXPORT_METHOD(multiSet:(NSArray<NSArray<NSString *> *> *)kvPairs
354399
callback:(RCTResponseSenderBlock)callback)
355400
{
401+
if (self.delegate != nil) {
402+
NSMutableArray<NSString *> *keys = [NSMutableArray arrayWithCapacity:kvPairs.count];
403+
NSMutableArray<NSString *> *values = [NSMutableArray arrayWithCapacity:kvPairs.count];
404+
for (NSArray<NSString *> *entry in kvPairs) {
405+
[keys addObject:entry[0]];
406+
[values addObject:entry[1]];
407+
}
408+
[self.delegate setValues:values forKeys:keys completion:^(NSArray<id<NSObject>> *results) {
409+
NSArray<NSDictionary *> *errors = RCTMakeErrors(results);
410+
callback(@[RCTNullIfNil(errors)]);
411+
}];
412+
return;
413+
}
414+
356415
NSDictionary *errorOut = [self _ensureSetup];
357416
if (errorOut) {
358417
callback(@[@[errorOut]]);
@@ -373,6 +432,20 @@ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL
373432
RCT_EXPORT_METHOD(multiMerge:(NSArray<NSArray<NSString *> *> *)kvPairs
374433
callback:(RCTResponseSenderBlock)callback)
375434
{
435+
if (self.delegate != nil) {
436+
NSMutableArray<NSString *> *keys = [NSMutableArray arrayWithCapacity:kvPairs.count];
437+
NSMutableArray<NSString *> *values = [NSMutableArray arrayWithCapacity:kvPairs.count];
438+
for (NSArray<NSString *> *entry in kvPairs) {
439+
[keys addObject:entry[0]];
440+
[values addObject:entry[1]];
441+
}
442+
[self.delegate mergeValues:values forKeys:keys completion:^(NSArray<id<NSObject>> *results) {
443+
NSArray<NSDictionary *> *errors = RCTMakeErrors(results);
444+
callback(@[RCTNullIfNil(errors)]);
445+
}];
446+
return;
447+
}
448+
376449
NSDictionary *errorOut = [self _ensureSetup];
377450
if (errorOut) {
378451
callback(@[@[errorOut]]);
@@ -407,8 +480,16 @@ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL
407480
}
408481

409482
RCT_EXPORT_METHOD(multiRemove:(NSArray<NSString *> *)keys
410-
callback:(RCTResponseSenderBlock)callback)
483+
callback:(RCTResponseSenderBlock)callback)
411484
{
485+
if (self.delegate != nil) {
486+
[self.delegate removeValuesForKeys:keys completion:^(NSArray<id<NSObject>> *results) {
487+
NSArray<NSDictionary *> *errors = RCTMakeErrors(results);
488+
callback(@[RCTNullIfNil(errors)]);
489+
}];
490+
return;
491+
}
492+
412493
NSDictionary *errorOut = [self _ensureSetup];
413494
if (errorOut) {
414495
callback(@[@[errorOut]]);
@@ -439,6 +520,17 @@ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL
439520

440521
RCT_EXPORT_METHOD(clear:(RCTResponseSenderBlock)callback)
441522
{
523+
if (self.delegate != nil) {
524+
[self.delegate removeAllValues:^(NSError *error) {
525+
NSDictionary *result = nil;
526+
if (error != nil) {
527+
result = RCTMakeError(error.localizedDescription, error, nil);
528+
}
529+
callback(@[RCTNullIfNil(result)]);
530+
}];
531+
return;
532+
}
533+
442534
[_manifest removeAllObjects];
443535
[RCTGetCache() removeAllObjects];
444536
NSDictionary *error = RCTDeleteStorageDirectory();
@@ -447,6 +539,13 @@ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL
447539

448540
RCT_EXPORT_METHOD(getAllKeys:(RCTResponseSenderBlock)callback)
449541
{
542+
if (self.delegate != nil) {
543+
[self.delegate allKeys:^(NSArray<id<NSObject>> *keys) {
544+
callback(@[(id)kCFNull, keys]);
545+
}];
546+
return;
547+
}
548+
450549
NSDictionary *errorOut = [self _ensureSetup];
451550
if (errorOut) {
452551
callback(@[errorOut, (id)kCFNull]);

ios/RNCAsyncStorage.xcodeproj/project.pbxproj

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
1990B94F223412A7009E5EA1 /* RNCAsyncStorageDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1990B9402233FE3A009E5EA1 /* RNCAsyncStorageDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
11+
1990B950223412B0009E5EA1 /* RNCAsyncStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = B3E7B5881CC2AC0600A0062D /* RNCAsyncStorage.h */; settings = {ATTRIBUTES = (Public, ); }; };
1012
B3E7B58A1CC2AC0600A0062D /* RNCAsyncStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNCAsyncStorage.m */; };
1113
/* End PBXBuildFile section */
1214

@@ -24,6 +26,7 @@
2426

2527
/* Begin PBXFileReference section */
2628
134814201AA4EA6300B7C361 /* libRNCAsyncStorage.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNCAsyncStorage.a; sourceTree = BUILT_PRODUCTS_DIR; };
29+
1990B9402233FE3A009E5EA1 /* RNCAsyncStorageDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNCAsyncStorageDelegate.h; sourceTree = "<group>"; };
2730
B3E7B5881CC2AC0600A0062D /* RNCAsyncStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNCAsyncStorage.h; sourceTree = "<group>"; };
2831
B3E7B5891CC2AC0600A0062D /* RNCAsyncStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNCAsyncStorage.m; sourceTree = "<group>"; };
2932
/* End PBXFileReference section */
@@ -52,19 +55,33 @@
5255
children = (
5356
B3E7B5881CC2AC0600A0062D /* RNCAsyncStorage.h */,
5457
B3E7B5891CC2AC0600A0062D /* RNCAsyncStorage.m */,
58+
1990B9402233FE3A009E5EA1 /* RNCAsyncStorageDelegate.h */,
5559
134814211AA4EA7D00B7C361 /* Products */,
5660
);
5761
sourceTree = "<group>";
5862
};
5963
/* End PBXGroup section */
6064

65+
/* Begin PBXHeadersBuildPhase section */
66+
1990B94E22341297009E5EA1 /* Headers */ = {
67+
isa = PBXHeadersBuildPhase;
68+
buildActionMask = 2147483647;
69+
files = (
70+
1990B94F223412A7009E5EA1 /* RNCAsyncStorageDelegate.h in Headers */,
71+
1990B950223412B0009E5EA1 /* RNCAsyncStorage.h in Headers */,
72+
);
73+
runOnlyForDeploymentPostprocessing = 0;
74+
};
75+
/* End PBXHeadersBuildPhase section */
76+
6177
/* Begin PBXNativeTarget section */
6278
58B511DA1A9E6C8500147676 /* RNCAsyncStorage */ = {
6379
isa = PBXNativeTarget;
6480
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNCAsyncStorage" */;
6581
buildPhases = (
6682
58B511D71A9E6C8500147676 /* Sources */,
6783
58B511D81A9E6C8500147676 /* Frameworks */,
84+
1990B94E22341297009E5EA1 /* Headers */,
6885
58B511D91A9E6C8500147676 /* CopyFiles */,
6986
);
7087
buildRules = (
@@ -204,7 +221,7 @@
204221
isa = XCBuildConfiguration;
205222
buildSettings = {
206223
HEADER_SEARCH_PATHS = (
207-
"$(inherited)",
224+
"$(inherited)",
208225
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
209226
"$(SRCROOT)/../../../React/**",
210227
"$(SRCROOT)/../../react-native/React/**",

ios/RNCAsyncStorageDelegate.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#import <Foundation/Foundation.h>
9+
10+
NS_ASSUME_NONNULL_BEGIN
11+
12+
typedef void (^RNCAsyncStorageCompletion)(NSError *_Nullable error);
13+
typedef void (^RNCAsyncStorageResultCallback)(NSArray<id<NSObject>> * valuesOrErrors);
14+
15+
@protocol RNCAsyncStorageDelegate <NSObject>
16+
17+
- (void)allKeys:(RNCAsyncStorageResultCallback)block;
18+
19+
- (void)mergeValues:(NSArray<NSString *> *)values
20+
forKeys:(NSArray<NSString *> *)keys
21+
completion:(RNCAsyncStorageResultCallback)block;
22+
23+
- (void)removeAllValues:(RNCAsyncStorageCompletion)block;
24+
25+
- (void)removeValuesForKeys:(NSArray<NSString *> *)keys
26+
completion:(RNCAsyncStorageResultCallback)block;
27+
28+
- (void)setValues:(NSArray<NSString *> *)values
29+
forKeys:(NSArray<NSString *> *)keys
30+
completion:(RNCAsyncStorageResultCallback)block;
31+
32+
- (void)valuesForKeys:(NSArray<NSString *> *)keys
33+
completion:(RNCAsyncStorageResultCallback)block;
34+
35+
@end
36+
37+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)