Tuesday, December 12, 2017

Access data stored in AsyncStorage from ios native code (objective c)

Leave a Comment

I need to access data stored in AsyncStorage from iOS native Objective C code.

This is needed to get the data in sync instead of sending App event to JS and then send it back to native code.

4 Answers

Answers 1

I've just been faced with the same problem.

My solution was to move the code native side.

On iOS:

#import <React/RCTAsyncLocalStorage.h> #import <React/RCTBridgeModule.h>  RCTResponseSenderBlock completion = ^(NSArray *response) {   NSString *theme = response[1][0][0][1];    // Setup RCTRootView with initialProperties };  RCTAsyncLocalStorage *storage = [[RCTAsyncLocalStorage alloc] init];  dispatch_async(storage.methodQueue, ^{   [storage performSelector:@selector(multiGet:callback:) withObject:@[@"theme"] withObject:completion]; }); 

You could additionally use dispatch_semaphore_wait to perform this synchronously

Update:

I needed the variable in the global state not just in the component props so the above doesn't go far enough.

I've had to work this into the React Native source at the point that the Javascript source is loaded.

NSString *javascriptPrepend = [NSString stringWithFormat:@"var ThemeMode = '%@';", self.theme]; NSMutableData *prependData = [[javascriptPrepend dataUsingEncoding:NSUTF8StringEncoding] mutableCopy]; [prependData appendData:sourceCode];  sourceCode = prependData;  

I'll see if they're open to a PR to allow this kind of functionality and post back here if I get it through.

Answers 2

Enhancing @luke’s solution – fixing an issue with the location of the data in the response; converting the JSON data to NSDictionary and ensuring the safety of the code – here is the complete method:

+(void)jsonFromLocalRNStrogeForKey:(NSString *)key completion:(void (^)(NSDictionary * _Nullable, NSError * _Nullable))completion {   RCTResponseSenderBlock rnCompletion = ^(NSArray *response) {      NSString *jsonAsString;      if (response.count > 1) {       NSArray *response1 = response[1];       if (response1.count > 0) {         NSArray *response2 = response1[0];          if (response2.count > 1) {           jsonAsString = response2[1];         }       }     }      NSData *jsonAsData = [jsonAsString dataUsingEncoding:NSUTF8StringEncoding];      NSError *error;      NSDictionary *json = [NSJSONSerialization                           JSONObjectWithData:jsonAsData                                                          options:NSJSONReadingMutableContainers                                                             error:&error];      completion(json, error);   };    RCTAsyncLocalStorage *storage = [RCTAsyncLocalStorage new];    dispatch_async(storage.methodQueue, ^{     [storage performSelector:@selector(multiGet:callback:) withObject:@[key] withObject:rnCompletion];   }); } 

Answers 3

My current solution. Which technically isn't a direct answer to the question but does offer a work-around for sharing data between Javascript and native code, is to use NSUserDefaults.

Using this package, react-native-default-preferences to easily persist the data into NSUserdefaults and then on the native side easily retrieve them as normal.

For my purposes I am persisting a token retrieved in Javascript, to be used later by extensions of the app. This means I also persist to a UserDefaults suite using the same key as my app.

React Native (Javascript):

DefaultPreference.setName('group.myApp'); DefaultPreference.set('TOKEN', token); 

Objective-C:

NSString *TOKEN = [[[NSUserDefaults alloc] initWithSuiteName:@"group.myApp"] stringForKey:@"TOKEN"]; 

Answers 4

I think you can use the code from the implementation AsyncStorage for this purpose. You can see it here. It basically loads the files that store the data using a NSFileManager and then parses them accordingly. In your case, have a look for instance at the multiGet method and then trace all the required functions present in the file. With that you should be able to re-implement them (or adapt) to fit your needs.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment