Skip to content

Commit ebfd705

Browse files
authored
[RN][iOS] Properly handle null values in TM interop layer (facebook#49291)
1 parent b96e948 commit ebfd705

File tree

4 files changed

+25
-16
lines changed

4 files changed

+25
-16
lines changed

packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTInteropTurboModule.mm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ T RCTConvertTo(SEL selector, id json)
346346
SEL selector = selectorForType(argumentType);
347347

348348
if ([RCTConvert respondsToSelector:selector]) {
349-
id objCArg = TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_);
349+
id objCArg = TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_, YES);
350350

351351
if (objCArgType == @encode(char)) {
352352
char arg = RCTConvertTo<char>(selector, objCArg);
@@ -500,7 +500,7 @@ T RCTConvertTo(SEL selector, id json)
500500
}
501501

502502
RCTResponseSenderBlock arg =
503-
(RCTResponseSenderBlock)TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_);
503+
(RCTResponseSenderBlock)TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_, YES);
504504
if (arg) {
505505
[retainedObjectsForInvocation addObject:arg];
506506
}
@@ -515,7 +515,7 @@ T RCTConvertTo(SEL selector, id json)
515515
}
516516

517517
RCTResponseSenderBlock senderBlock =
518-
(RCTResponseSenderBlock)TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_);
518+
(RCTResponseSenderBlock)TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_, YES);
519519
RCTResponseErrorBlock arg = ^(NSError *error) {
520520
senderBlock(@[ RCTJSErrorFromNSError(error) ]);
521521
};
@@ -545,7 +545,7 @@ T RCTConvertTo(SEL selector, id json)
545545
runtime, errorPrefix + "JavaScript argument must be a plain object. Got " + getType(runtime, jsiArg));
546546
}
547547

548-
id arg = TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_);
548+
id arg = TurboModuleConvertUtils::convertJSIValueToObjCObject(runtime, jsiArg, jsInvoker_, YES);
549549

550550
RCTManagedPointer *(*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend;
551551
RCTManagedPointer *box = convert([RCTCxxConvert class], selector, arg);

packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ using EventEmitterCallback = std::function<void(const std::string &, id)>;
3232
namespace TurboModuleConvertUtils {
3333
jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value);
3434
id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<CallInvoker> jsInvoker);
35+
id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<CallInvoker> jsInvoker, BOOL useNSNull);
3536
} // namespace TurboModuleConvertUtils
3637

3738
template <>

packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,28 +112,28 @@ static int32_t getUniqueId()
112112
}
113113

114114
static NSArray *
115-
convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value, std::shared_ptr<CallInvoker> jsInvoker)
115+
convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value, std::shared_ptr<CallInvoker> jsInvoker, BOOL useNSNull)
116116
{
117117
size_t size = value.size(runtime);
118118
NSMutableArray *result = [NSMutableArray new];
119119
for (size_t i = 0; i < size; i++) {
120120
// Insert kCFNull when it's `undefined` value to preserve the indices.
121-
id convertedObject = convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i), jsInvoker);
121+
id convertedObject = convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i), jsInvoker, useNSNull);
122122
[result addObject:convertedObject ? convertedObject : (id)kCFNull];
123123
}
124124
return [result copy];
125125
}
126126

127127
static NSDictionary *
128-
convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value, std::shared_ptr<CallInvoker> jsInvoker)
128+
convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value, std::shared_ptr<CallInvoker> jsInvoker, BOOL useNSNull)
129129
{
130130
jsi::Array propertyNames = value.getPropertyNames(runtime);
131131
size_t size = propertyNames.size(runtime);
132132
NSMutableDictionary *result = [NSMutableDictionary new];
133133
for (size_t i = 0; i < size; i++) {
134134
jsi::String name = propertyNames.getValueAtIndex(runtime, i).getString(runtime);
135135
NSString *k = convertJSIStringToNSString(runtime, name);
136-
id v = convertJSIValueToObjCObject(runtime, value.getProperty(runtime, name), jsInvoker);
136+
id v = convertJSIValueToObjCObject(runtime, value.getProperty(runtime, name), jsInvoker, useNSNull);
137137
if (v) {
138138
result[k] = v;
139139
}
@@ -159,11 +159,14 @@ static int32_t getUniqueId()
159159
};
160160
}
161161

162-
id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<CallInvoker> jsInvoker)
162+
id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<CallInvoker> jsInvoker, BOOL useNSNull)
163163
{
164-
if (value.isUndefined() || value.isNull()) {
164+
if (value.isUndefined() || (value.isNull() && !useNSNull)) {
165165
return nil;
166166
}
167+
if (value.isNull() && useNSNull) {
168+
return [NSNull null];
169+
}
167170
if (value.isBool()) {
168171
return @(value.getBool());
169172
}
@@ -176,17 +179,22 @@ id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, s
176179
if (value.isObject()) {
177180
jsi::Object o = value.getObject(runtime);
178181
if (o.isArray(runtime)) {
179-
return convertJSIArrayToNSArray(runtime, o.getArray(runtime), jsInvoker);
182+
return convertJSIArrayToNSArray(runtime, o.getArray(runtime), jsInvoker, useNSNull);
180183
}
181184
if (o.isFunction(runtime)) {
182185
return convertJSIFunctionToCallback(runtime, o.getFunction(runtime), jsInvoker);
183186
}
184-
return convertJSIObjectToNSDictionary(runtime, o, jsInvoker);
187+
return convertJSIObjectToNSDictionary(runtime, o, jsInvoker, useNSNull);
185188
}
186189

187190
throw std::runtime_error("Unsupported jsi::Value kind");
188191
}
189192

193+
id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<CallInvoker> jsInvoker)
194+
{
195+
return convertJSIValueToObjCObject(runtime, value, jsInvoker, NO);
196+
}
197+
190198
static jsi::Value createJSRuntimeError(jsi::Runtime &runtime, const std::string &message)
191199
{
192200
return runtime.global().getPropertyAsFunction(runtime, "Error").call(runtime, message);

packages/rn-tester/Podfile.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1888,12 +1888,12 @@ EXTERNAL SOURCES:
18881888
:path: "../react-native/ReactCommon/yoga"
18891889

18901890
SPEC CHECKSUMS:
1891-
boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90
1892-
DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb
1891+
boost: 4cb898d0bf20404aab1850c656dcea009429d6c1
1892+
DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5
18931893
fast_float: 06eeec4fe712a76acc9376682e4808b05ce978b6
18941894
FBLazyVector: a2db46e659b982d7193563db43dfc90c9a213074
18951895
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
1896-
glog: eb93e2f488219332457c3c4eafd2738ddc7e80b8
1896+
glog: 69ef571f3de08433d766d614c73a9838a06bf7eb
18971897
hermes-engine: d152d4b5b123cb9abbd21183ed7783e067314c76
18981898
MyNativeView: ba8324184f90f76b5051af6716faa458d4d63b51
18991899
NativeCxxModuleExample: ad2c1a2c0def6c6a1bf5f1257e6bc372b806aea5
@@ -1966,4 +1966,4 @@ SPEC CHECKSUMS:
19661966

19671967
PODFILE CHECKSUM: 8591f96a513620a2a83a0b9a125ad3fa32ea1369
19681968

1969-
COCOAPODS: 1.15.2
1969+
COCOAPODS: 1.14.3

0 commit comments

Comments
 (0)