Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react-native iOS native module: calling method that activates network indicator asynchronously

I am writing a native module that calls functions from a closed source framework binary that I don't have access to. It makes blocking network calls and activates the network indicator. I want to be able to run it in the background asyncronously, It kind of works out of the box, but when I do that I get this warning/error and the call stalls a bit:

Main Thread Checker: UI API called on a background thread: -[UIApplication setNetworkActivityIndicatorVisible:]

If I put it on the main queue using the following code in my In my RN Module, the calls block everything until they complete.

- (dispatch_queue_t)methodQueue
{
  return dispatch_get_main_queue();
}

Here is an example of a method exposed to JS:

RCT_REMAP_METHOD(createSession,
                 userIDtoken:(NSString *)userIDtoken
                 createSessionWithResolver:(RCTPromiseResolveBlock)resolve
                 rejecter:(RCTPromiseRejectBlock)reject)
{
    Boolean connected = [_networkController startSession:userIDtoken isTest:true];
    NSString *success = @"session created";
    if (connected){
      resolve(success);
    } else {
      NSError *error = [NSError errorWithDomain:@"ConnectionError" code:1 userInfo:nil];
      reject(@"session_creation_failed", @"Cannot create sessions", error);
    }
}

_networkController startSession should run in the background without throwing the warning/error and without blocking the main thread. Is there a way to do this?

like image 943
Christopher Reid Avatar asked Aug 27 '19 17:08

Christopher Reid


People also ask

What is React Native and how does it work?

React Native consists of Javascript code controlling Native UI. An React component will display a native UIImage on iOS. So React Native is essentially Native! If you open your React Native app in the XCode hierarchy inspector, you’ll indeed see the Native UI components. The first challenge that we need to tackle is how to handle navigation.

How to call Objective-C methods in React Native from JavaScript?

When a native module method is invoked in JavaScript, React Native converts the arguments from JS objects to their Objective-C/Swift object analogues. So for example, if your Objective-C Native Module method accepts a NSNumber, in JS you need to call the method with a number. React Native will handle the conversion for you.

What is React Native turbomodules?

The React Native team is currently working on a re-architecture of the Native Module system. This new system is called TurboModules, and it will help facilitate more efficient type-safe communication between JavaScript and native, without relying on the React Native bridge.

How do I use calendarmanager with React Native bridge?

The CalendarManager module is instantiated on the Objective-C side using a call. The return type of bridge methods is always void. React Native bridge is asynchronous, so the only way to pass a result to JavaScript is by using callbacks or emitting events (see below).


1 Answers

You cannot make UIKit API calls on a background thread as it is not thread-safe.

You can remove the RN module methodQueue setup so your module's method will get called once again on a background thread and will not block the main thread. Whenever you need to make a call to [UIApplication setNetworkActivityIndicatorVisible:] (or any other method that requires the main queue), you can dispatch it to the main thread, for example:

dispatch_async(dispatch_get_main_queue(), ^{
    [UIApplication.sharedApplication setNetworkActivityIndicatorVisible:YES];
});

In case you need to resolve the promise only after setting the activity indicator, you can also put your calls to resolve/reject inside the same block after changing the activity indicator visibility.

like image 65
Artal Avatar answered Nov 10 '22 12:11

Artal