Skip to content

[iOS] Turbo module: Fixes dictionary stripped out when value is null - #51103

Closed
zhongwuzw wants to merge 13 commits into
react:mainfrom
zhongwuzw:features/fix_dictionary_not_passed_nil_value
Closed

zhongwuzw wants to merge 13 commits into
react:mainfrom
zhongwuzw:features/fix_dictionary_not_passed_nil_value

Conversation

@zhongwuzw

@zhongwuzw zhongwuzw commented May 5, 2025 •

Copy link
Copy Markdown
Contributor

Summary:

Fixes #51083. Turbo stripped out the dictionary when the value is null. The old architecture transforms null to NSNull. The null seems useful in cases like #51803 for removing the storage of the key. @cipolleschi can you please help to review?

Changelog:

[IOS] [FIXED] - Turbo module: Fixes dictionary stripped out when value is null

Test Plan:

Repro please see #51083.

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. labels May 5, 2025
@facebook-github-bot

Copy link
Copy Markdown
Contributor

@philIip has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@cipolleschi

Copy link
Copy Markdown
Contributor

Hi @zhongwuzw! thanks for the PR.
I'm not sure we can land this. I know that this is a semantic change between the Old and the New Architecture. However this might be a deliberate design decision, made before me joining the team. I'll have to investigate.

Internally, we have several pieces of code that relies on the null values being removed from the dictionary, so by landing this, we are going to break that code. Similarly, we might be breaking New Arch libraries that do not expect receiving NSNull.

@zhongwuzw

Copy link
Copy Markdown
Contributor Author

Hi @zhongwuzw! thanks for the PR.

I'm not sure we can land this. I know that this is a semantic change between the Old and the New Architecture. However this might be a deliberate design decision, made before me joining the team. I'll have to investigate.

Internally, we have several pieces of code that relies on the null values being removed from the dictionary, so by landing this, we are going to break that code. Similarly, we might be breaking New Arch libraries that do not expect receiving NSNull.

@cipolleschi Thanks for the review. If we don't support null vaule of dictionary, we should seems make the native module like setting module add a removeKey api to not passed dictionary?

@javache

javache commented May 6, 2025

Copy link
Copy Markdown
Contributor

Thanks for fixing this! I think this absolutely needs a unit test to show how the behaviour changes before/after.

id (*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend;
id convertedObjCArg = convert([RCTConvert class], rctConvertSelector, objCArg);

if (objCArg == [NSNull null]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be looking at convertedObjCArg instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhongwuzw: that doesn't seem right. RCTInteropTurboModule looks at arg, which is the return value of the RCTConvertTo call (we should probably use that RCTConvertTo helper here too!) - so the equivalent would be to use convertedObjCArg here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, you're right. 👍 updated.

@cipolleschi

Copy link
Copy Markdown
Contributor

As @javache was mentioning, we discussed this internally and we want to pull in the fix.
However, this change might break quite a few stuff, so we need to be cautious about how we do it.
for sure we will need:

  1. a unit test
  2. a feature flag, that we can use to revert to the previous behavior in case too many things start to go very bad. We have a good infrastructure for feature flags: you can modify the featureflag.config.js to add it. Then yarn featureflags --update should generate all the required files. Then you should import the feature flag and use it.

Do you mind applying these changes?

@zhongwuzw

Copy link
Copy Markdown
Contributor Author

@cipolleschi Got it. I'll try to do them.

@cipolleschi

Copy link
Copy Markdown
Contributor

I tried to apply this fix to a test that I was doing for #51083, but it does not fixes.
I was using this repo as test bed: https://github.com/cipolleschi/TMDroppingNull

It contains both a legacy native module and a turbomodule.

The expectation is that both should receive

{
  "key": "myKey",
  "value": "<null>"
}

when pressing the Save Null button in the UI

@zhongwuzw

zhongwuzw commented May 11, 2025 •

Copy link
Copy Markdown
Contributor Author

@cipolleschi Hi, I tried, seems I received the null value.
LegacyNativeModule:
image

turbomodule;
image

BTW, can you help me how to write a test? I don't know wether unit test needs some env requirements? Seems I only see the old bridge related unit test. I used RNTester RNTesterUnitTests schema.

id objCArg = convertJSIValueToObjCObject(runtime, arg, jsInvoker_);
BOOL enableModuleArgumentNSNullConversionIOS = ReactNativeFeatureFlags::enableModuleArgumentNSNullConversionIOS();
id objCArg = TurboModuleConvertUtils::convertJSIValueToObjCObject(
runtime, arg, jsInvoker_, enableModuleArgumentNSNullConversionIOS);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we passing enableModuleArgumentNSNullConversionIOS to the convertJSIValueToObjCObject function?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We enable useNull only if we set enableModuleArgumentNSNullConversionIOS to true to convert null to NSNull. If we don't enable enableModuleArgumentNSNullConversionIOS, everything remains the same as original.

@cipolleschi

cipolleschi commented May 14, 2025 •

Copy link
Copy Markdown
Contributor

~~I tried again with the repo I prepared and I don't get the same result as you. 😰 ~~

My bad, I realized that I applied badly your suggestion.


For the unit test, I'm not sure we have something set up in OSS. I'll have to investigate a bit and get back to you.

@javache

javache commented May 15, 2025

Copy link
Copy Markdown
Contributor

I'm adding a test in #51370 - which we should be able to use verify this changes fixes it once you enable the feature flag.

@javache

javache commented May 20, 2025

Copy link
Copy Markdown
Contributor

Can you update the test and add a variant that shows the behaviour you get when overriding the feature flag?

@zhongwuzw

Copy link
Copy Markdown
Contributor Author

@javache Hi, can you tell me how to run the test? I already merged your commit https://github.com/facebook/react-native/blob/6d25274a522c993529e6dc1da8da7af62247a8ab/packages/react-native/ReactCommon/react/nativemodule/core/iostests/RCTTurboModuleTests.mm#L89 and I see it already added dictionary null value check, I don't know why my pr's ci is all passed, my featureflag is enabled by default.

@facebook-github-bot

Copy link
Copy Markdown
Contributor

@javache has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@javache

javache commented May 21, 2025

Copy link
Copy Markdown
Contributor

Ah, we probably don't have these tests setup for OSS CI :( I'll run it internally

@facebook-github-bot

Copy link
Copy Markdown
Contributor

@javache has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@javache

javache commented May 21, 2025

Copy link
Copy Markdown
Contributor

Could you try updating the PR? I'm having trouble importing it.

@zhongwuzw

Copy link
Copy Markdown
Contributor Author

@javache Hi, I updated .

@facebook-github-bot

Copy link
Copy Markdown
Contributor

@javache has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

javache pushed a commit to javache/react-native that referenced this pull request May 23, 2025
…#51103)

Summary:
Fixes react#51083. Turbo stripped out the dictionary when the value is null. The old architecture transforms null to NSNull. The null seems useful in cases like react#51803 for removing the storage of the key. cipolleschi can you please help to review?

## Changelog:

[IOS] [FIXED] - Turbo module: Fixes dictionary stripped out when value is null

Pull Request resolved: react#51103

Test Plan: Repro please see react#51083.

Differential Revision: D74208525

Pulled By: javache
@react-native-bot

Copy link
Copy Markdown
Collaborator

This pull request was successfully merged by @zhongwuzw in 4a4fd1c

When will my fix make it into a release? | How to file a pick request?

@react-native-bot react-native-bot added the Merged This PR has been merged. label May 23, 2025
@facebook-github-bot

Copy link
Copy Markdown
Contributor

@javache merged this pull request in 4a4fd1c.

javache added a commit to javache/react-native that referenced this pull request May 23, 2025
Summary:
This is causing some internal test failures for now, so disabling the behaviour to prevent further rollout.

Changelog: [iOS] Disable fix for react#51103 until more testing can be done.

Differential Revision: D75320842
facebook-github-bot pushed a commit that referenced this pull request May 23, 2025
Summary:
Pull Request resolved: #51576

This is causing some internal test failures for now, so disabling the behaviour to prevent further rollout.

Changelog: [iOS][Removed] Disable fix for #51103 until more testing can be done.

Differential Revision: D75320842

fbshipit-source-id: 39c115afd11e5b1aca6cdc1fc18ec7e83eb10382
@javache

javache commented May 27, 2025

Copy link
Copy Markdown
Contributor

This change caused some internal issues, so I disabled it by default again, I'll try to debug more but this may affect other new architecture users too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[iOS] Settings no longer handles setting key to null

5 participants