Fabric: Unifying retain/release logic in EventTarget

Summary:
I read my code and one thing stroke me: What if the same event emitter dispatches several events during the same event beat? In the previous implementation, only the first one will be delivered because the first `release` call consumes stored strong reference.
So, I changed the API a bit to make this more explicit: we have `retain` & `release` methods and we have a getter that works (multiple times) only if the object was successfully retained.

Reviewed By: sahrens

Differential Revision: D13668147

fbshipit-source-id: c00af5f15bc7e30aa704d46bd23584b918b6f75a
This commit is contained in:
Valentin Shergin 2019-01-16 20:17:01 -08:00 committed by Facebook Github Bot
parent 7d630b92dc
commit 8d83d5f8eb
4 changed files with 28 additions and 7 deletions

View File

@ -53,6 +53,13 @@ void EventQueue::onBeat(jsi::Runtime &runtime) const {
eventPipe_(
runtime, event.eventTarget.get(), event.type, event.payloadFactory);
}
// No need to lock `EventEmitter::DispatchMutex()` here.
for (const auto &event : queue) {
if (event.eventTarget) {
event.eventTarget->release(runtime);
}
}
}
} // namespace react

View File

@ -42,11 +42,20 @@ void EventTarget::retain(jsi::Runtime &runtime) const {
assert(!strongInstanceHandle_.isUndefined());
}
jsi::Value EventTarget::release(jsi::Runtime &runtime) const {
void EventTarget::release(jsi::Runtime &runtime) const {
// The method does not use `jsi::Runtime` reference.
// It takes it only to ensure thread-safety (if the caller has the reference,
// we are on a proper thread).
return std::move(strongInstanceHandle_);
strongInstanceHandle_ = jsi::Value::null();
}
jsi::Value EventTarget::getInstanceHandle(jsi::Runtime &runtime) const {
if (strongInstanceHandle_.isNull()) {
// The `instanceHandle` is not retained.
return jsi::Value::null();
}
return jsi::Value(runtime, strongInstanceHandle_);
}
Tag EventTarget::getTag() const {

View File

@ -43,16 +43,21 @@ class EventTarget {
void setEnabled(bool enabled) const;
/*
* Creates a strong instance handle from a weak one and stores it inside the
* object.
* Retains an instance handler by creating a strong reference to it.
* If the EventTarget is disabled, does nothing.
*/
void retain(jsi::Runtime &runtime) const;
/*
* Extract the stored strong instance handle from the object and returns it.
* Releases the instance handler by nulling a strong reference to it.
*/
jsi::Value release(jsi::Runtime &runtime) const;
void release(jsi::Runtime &runtime) const;
/*
* Creates and returns the `instanceHandle`.
* Returns `null` if the `instanceHandle` is not retained at this moment.
*/
jsi::Value getInstanceHandle(jsi::Runtime &runtime) const;
/*
* Deprecated. Do not use.

View File

@ -74,7 +74,7 @@ void UIManagerBinding::dispatchEvent(
auto instanceHandle = eventTarget
? [&]() {
auto instanceHandle = eventTarget->release(runtime);
auto instanceHandle = eventTarget->getInstanceHandle(runtime);
if (instanceHandle.isUndefined()) {
return jsi::Value::null();
}