Skip to content

Commit cc87e6e

Browse files
committed
fix(ffi): fall back to the call's receiver when a bound one has gone away
(cherry picked from commit 869f7dbf1fd823dc425183e71f79f22cf5bd2d7d)
1 parent 48a1950 commit cc87e6e

2 files changed

Lines changed: 18 additions & 4 deletions

File tree

NativeScript/ffi/objc/hermes/NativeApiJsi.mm

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,13 @@ NativeApiSelectorGroupState state(
192192
}
193193
if (state.boundReceiverState != nullptr) {
194194
receiverHostObject = state.boundReceiver.lock();
195-
} else if (thisValue.isObject()) {
195+
}
196+
// Fall through rather than else-if: the bound receiver is weak, so a
197+
// collected wrapper leaves it empty, and the call still has a perfectly
198+
// good receiver in thisValue. Binding must not turn a live call into
199+
// "requires a native receiver". SelectorGroupCall.h already resolves it
200+
// this way; this lambda was the one place that did not.
201+
if (!receiverHostObject && thisValue.isObject()) {
196202
Object receiverObject = thisValue.asObject(runtime);
197203
if (receiverObject.isHostObject<NativeApiObjectHostObject>(
198204
runtime)) {

NativeScript/ffi/objc/shared/bridge/SelectorGroupCall.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,17 @@ inline NativeApiResolvedSelectorGroupCall resolveNativeApiSelectorGroupCall(
3434
result.receiver =
3535
data.receiverIsClass ? static_cast<id>(data.lookupClass) : nil;
3636
if (!data.receiverIsClass) {
37-
result.receiver = data.boundReceiverState != nullptr
38-
? data.boundReceiverState->object()
39-
: resolveReceiver();
37+
// The bound receiver's lifetime state is cleared when its ObjC object goes
38+
// away, so "bound" does not mean "still has an object". Falling back to the
39+
// call's own receiver keeps a live call working; the ternary turned it into
40+
// "requires a native receiver". This mirrors how the init path below
41+
// resolves the receiver host.
42+
if (data.boundReceiverState != nullptr) {
43+
result.receiver = data.boundReceiverState->object();
44+
}
45+
if (result.receiver == nil) {
46+
result.receiver = resolveReceiver();
47+
}
4048
}
4149
if (result.receiver == nil) {
4250
throw JSError(runtime,

0 commit comments

Comments
 (0)