Reputation: 413
TLDR: Is there some way I can use a callback or get a return value from react to my native code (iOS)? Or can I use a set of locks to enforce ordering for eventdispatcher and eventemitter listeners to enforce an ordering?
More Information:
So I'm using the event dispatcher in my iOS code (self.bridge.eventDispatcher) and that's working great. I'm able to send events with information to my react code.
However, I noticed that this works asynchronously. I currently use this because if I require information on my iOS side, I send a ping to my react side requesting this information. I then lock upon the request and wait for my react code to use NativeModules and invoke an iOS method where I get the requested data.
Basically, enforcing a synchronous pattern feels a little dangerous because I'm not sure whether bridging methods can fail. For example, I can send an event to react and then lock. If my react side does not get it, or fails to send a notification to the iOS side, then I will never unlock and then will have deadlock. So to this, I have two questions. Is bridging reliable enough to avoid deadlocking through this method? Or is there a better way to accomplish the same result and request information from my react side from my iOS code?
Upvotes: 1
Views: 687
Reputation: 413
Awesome so I got it, turns out there's a structure called RCTResponseSenderBlock. I made another
iOS method:
-(void)tmpMethod:(RCTResponseSenderBlock)callback{
[self.bridge.eventDispatcher sendAppEventWithName:@"channel" body:@{@"Block":callback}
] ;
}
javascriptReciever:
EventEmitter.addListener("channel", async event => {
console.log(event)
event.Block(["Hello There"]);
return;
});
ios Method Invocation:
[self tmpMethod:^(NSArray* response){
NSLog((NSString*)[response objectAtIndex:0]); //prints Hello There
}];
UPDATE Turns out when I try to do the same for Android, I can't. The Android platform uses WriteableMap or WriteableArray to send events using the following method:
private void sendEvent(ReactContext reactContext,
String eventName,
@Nullable WritableMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
WriteableMap and WriteableArray both do not accept objects such as callbacks which made it not possible to request information from the Javascript side. I also attempted to pass in a Promise as opposed to a WriteableMap or WriteableArray and that threw an error. To communicate asynchronously in a synchronous context for android,
- I will have to send an event from native to javascript
- lock twice to prevent further execution in side native
- on my javascript side invoke a method on my native side once viewing the request with the requested data
- unlock within the native method invoked by javascript
- resume execution since the program has been unlocked
- unlock once further after handling whatever needed to be handled synchronously. (Comment if you want my code implementation)
EDIT AGAIN: The above flow didn't work. I don't have any control over threads in Android since ReactNative always uses the main thread. So if I end up locking the main thread then react-native cannot enter another method to unlock, thus I have deadlock. So not possible to enforce synchronous exchange of data with android.
Upvotes: 1