[iOS] Script init caches the wrong view model when dataBind is applied after state-machine creation
Maintainers usually reply within 1 day
A pull request for this has already been merged.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 63/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- react-native, swift, typescript
Research direction
Read ios/new/RiveReactNativeView.swift, focusing on state-machine creation and dataBind resolution. Compare the current order with the supplied standalone Swift probe and proposed diff, then run the iOS reproduction with RiveRuntime 6.28.0. Done means the explicitly bound host instance is used at state-machine creation, so the probe reports isReady: 1 and observedSeed: 42; Android and the legacy backend are outside the reported validation.
Written by the indexing model from the issue text.
Description
Description
On the iOS new runtime, supplying an explicit view-model instance through <RiveView dataBind={instance}> can leave a Luau script reading and writing the authored default instance instead of the host instance.
The script caches context:viewModel() in init. The React Native wrapper creates the state machine before passing the explicit instance into Rive(...dataBind: .instance(...)). The script appears to initialize against the default instance during state-machine creation and retain that reference after the host model is bound.
This has a functional consequence beyond the deprecated-API warnings tracked in #403: host initialization values are invisible to the script, and script-written readiness/results never reach the host's instance. In a small probe, the host seeds seed = 42, the script sets isReady = 1 in init, and each advance copies its cached model's seed into observedSeed.
| Value read from the host instance after 2 seconds | Current order | Bind at state-machine creation | Expected |
|---|---|---|---|
| seed | 42 | 42 | 42 |
| isReady | 0 | 1 | 1 |
| observedSeed | 0 | 42 | 42 |
The current-order rectangle renders red (script sees seed 0), while the early-binding rectangle renders green (script sees seed 42). There is no crash or script exception.
Minimal reproduction and source file
Complete standalone reproduction
The gist includes:
- A 17,434-byte signed
.rivfixture, base64-encoded because gists do not accept binary files, with a decode command and SHA-256 checksum. No CLI login is required to run the supplied file. - Complete
scene.rml,probe.luau, andrive.yamlsource: one artboard, one state machine, one script, three numbers; no application assets. - A runnable
main.swift+run-ios.pyprobe that tests both initialization orders side by side using RiveRuntime 6.28.0. It prints results and asserts both outcomes. - Actual
results.json, a minimal React NativeApp.tsxadapter, andproposed-fix.diff.
Verified native repro steps
- Clone/download the gist and decode
binding-init-repro.riv.b64using the command in its README. - Download the official RiveRuntime 6.28.0 XCFramework.
- With an Apple Silicon iOS simulator booted, run
python3 run-ios.py /path/to/RiveRuntime.xcframework. - Observe
lateBinding: {seed: 42, isReady: 0, observedSeed: 0}andbindingAtCreation: {seed: 42, isReady: 1, observedSeed: 42}.
Both cases create independent artboards and host model instances from the same file. Both seed the model before state-machine creation and use the same deprecated Rive(...dataBind: .instance(model)) initializer afterward. The only difference is supplying binding: model to createStateMachine.
React Native usage
The App.tsx adapter uses useViewModelInstance(riveFile, { async: true, viewModelName: 'ProbeModel', onInit }), seeds seed = 42 in onInit, and mounts RiveView only after the instance exists:
<RiveView
file={riveFile}
artboardName="Binding Probe"
stateMachineName="Main"
dataBind={instance}
autoPlay
fit={Fit.Layout}
style={{ width: 160, height: 160 }}
/>
Use a native development build, add riv to Metro's assetExts, and leave the default iOS new backend enabled. The gist has the complete component and setup notes.
Likely cause / small workaround
The relevant current code is in ios/new/RiveReactNativeView.swift at v0.5.4. It calls createStateMachine(config.stateMachineName) before resolving dataBind and constructing Rive.
Moving state-machine creation after binding resolution and using the explicit-instance overload fixes the isolated probe:
let stateMachine: StateMachine
if case .instance(let vmi) = dataBind {
stateMachine = try await artboard.createStateMachine(
config.stateMachineName, binding: vmi
)
} else {
stateMachine = try await artboard.createStateMachine(config.stateMachineName)
}
The Rive iOS 6.28.0 release guidance also supplies the model at state-machine creation. The attached diff is a narrow workaround for initial explicit-instance binding, not a complete migration or a claim to fix later instance replacement. The broader auto/by-name/rebinding migration can stay under #403.
Environment / validation scope
- Original affected application:
@rive-app/react-native0.5.3, React Native 0.86.0, Expo SDK 57,react-native-nitro-modules0.36.5. - Runtime: iOS new backend, RiveRuntime 6.28.0.
- Standalone Swift repro actually executed on iPhone 17 Pro simulator, iOS 26.5; recorded results are in the gist.
- Latest 0.5.4 source inspected: the relevant initialization order is unchanged and its
runtimeVersions.iosis also 6.28.0. I have not separately run a complete 0.5.4 React Native app. - The generic
App.tsxadapter type-checks against 0.5.3; the executed isolated test is the Swift probe, which follows the wrapper's native initialization sequence. - Android and the legacy iOS backend: not tested for this issue.
- Previous working version: not established.
- Fixture authored with Rive CLI 1.3.0, signed and watermarked. It executes in both native cases, so this is not an unsigned-script rejection.
I searched existing issues and found #403 related, but did not find a report for this specific cached-script-model behavior. Happy to consolidate this reproduction into #403 if that is preferable.
- Dominant language
- TypeScript
- Stars
- 155
- Forks
- 17
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 20
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from rive-app/rive-nitro-react-native
-
[Android] Fit.Layout content stale after resize on the new backend (surface keeps creation size)Possibly taken @mfazekas claimed this 3 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 25/100
rive-app/rive-nitro-react-native#418 ·
Maintainers usually reply within 1 day
-
Rive drains battery in the background on AndroidPossibly taken @mfazekas claimed this 5 days ago. Openandroid bug
Difficulty 4/5 3-5 days Newbie friendliness 48/100
rive-app/rive-nitro-react-native#413 ·
Maintainers usually reply within 1 day
-
[Android] RiveFonts: loadFont({name}) fails for script fonts on OEM fonts.xml; systemFallback() is not script-aware (tofu for Thai/Hebrew/Arabic/CJK)Possibly taken @mfazekas claimed this 13 days ago. Openandroid bug
Difficulty 3/5 1-2 days Newbie friendliness 65/100
rive-app/rive-nitro-react-native#369 · 3 comments ·
Maintainers usually reply within 1 day
-
enhancement iOS
Difficulty 4/5 3-5 days Newbie friendliness 35/100
rive-app/rive-nitro-react-native#58 · 7 comments ·
Maintainers usually reply within 1 day
All issues in rive-app/rive-nitro-react-native
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
callstackincubator/simlock#639 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
aws/agentcore-cli#2606 ·
Maintainers usually reply within 1 day
-
ai-driven-qa bug Cosmetic
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Maintainers usually reply within 1 day
-
ai-driven-qa bug claude Minor
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
linagora/twake-mail-admin#301 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day