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?
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.
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.
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.
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With