Skip to content

Add native SwiftUI.Bindable support for iOS 17+ - #389

Merged
johnnewman-square merged 5 commits into
mainfrom
jn/native-bindable-ios17
Apr 10, 2026
Merged

Add native SwiftUI.Bindable support for iOS 17+#389
johnnewman-square merged 5 commits into
mainfrom
jn/native-bindable-ios17

Conversation

@johnnewman-square

@johnnewman-square johnnewman-square commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

This adds support for the .sending(...) API on iOS 17+ Bindables. The original implementation worked with Perception.Bindable, which is marked as obsolete on 17+, requiring clients to switch to SwiftUI.Bindable where these APIs didn't previously exist.

Summary

  • Adds _NativeStoreBindable, a native @Bindable equivalent of _StoreBindable for iOS 17+ clients, supporting all three .sending() overloads (sink:action:, closure:, and action: for SingleActionModel)
  • Suppresses false-positive Perception runtime warnings on iOS 17+ by setting skipPerceptionChecking in Store's state-reading and child-store scoping paths, where the Perceptible overload of PerceptionRegistrar.access is selected at compile time even though native observation is tracking
  • Adds four native binding tests in StoreTests mirroring the existing Perception.Bindable tests, using XCTSkip to skip on iOS 16
  • Adds NativeMultiCounterView sample demonstrating @Bindable usage without WithPerceptionTracking, wired via #available in MultiCounterScreen

Test plan

  • Run WorkflowSwiftUI-Tests on an iOS 17+ simulator — verify the 4 native binding tests pass
  • Run WorkflowSwiftUI-Tests on an iOS 16 simulator — verify the native binding tests are skipped via XCTSkip and existing tests still pass
  • Build and run the ObservableComposition sample on iOS 17+ — verify NativeMultiCounterView is used with no Perception runtime warnings
  • Build and run the ObservableComposition sample on iOS 16 — verify MultiCounterView is used as fallback

🤖 Generated with Claude Code

Clients with a minimum deployment target of iOS 17 can now use
SwiftUI's native @bindable property wrapper with Store, including
the .sending(action:) API for custom action routing.

- Add _NativeStoreBindable, mirroring _StoreBindable for native
  @bindable instead of @Perception.Bindable
- Suppress false-positive Perception runtime warnings on iOS 17+ by
  setting skipPerceptionChecking in Store's state-reading paths
- Add NativeBindableStoreTests covering all three sending overloads
- Add NativeMultiCounterView sample demonstrating @bindable usage
  without WithPerceptionTracking

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@johnnewman-square
johnnewman-square force-pushed the jn/native-bindable-ios17 branch from 07d1637 to 9b46641 Compare April 9, 2026 15:12
johnnewman-square and others added 2 commits April 9, 2026 11:24
Replace @available annotations with guard #available + XCTSkip to
prevent XCTest from failing on iOS 16 when it discovers but cannot
execute availability-gated test methods.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@johnnewman-square
johnnewman-square marked this pull request as ready for review April 9, 2026 18:20
@johnnewman-square
johnnewman-square requested review from a team as code owners April 9, 2026 18:20
@johnnewman-square

Copy link
Copy Markdown
Contributor Author

@codex review

Comment thread WorkflowSwiftUI/Sources/Bindable+Store.swift
Comment thread WorkflowSwiftUI/Tests/StoreTests.swift
Add iOS 17+ @bindable examples to the adoption guide and a native
child-store observation test to cover the skipPerceptionChecking
suppression in Store.access(). Fix trailing whitespace in test markers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@johnnewman-square

Copy link
Copy Markdown
Contributor Author

@robmaceachern I have addressed the feedback, thanks again. One thing I wanted to be sure to mention is that the WithPerceptionTracking warning logs will now be suppressed on iOS 17+ with these changes. They will still log on iOS 16.

@johnnewman-square
johnnewman-square merged commit def2ffe into main Apr 10, 2026
15 checks passed
@johnnewman-square
johnnewman-square deleted the jn/native-bindable-ios17 branch April 10, 2026 21:01
johnnewman-square added a commit that referenced this pull request Apr 21, 2026
This PR builds on the changes from
#389.

## Summary
- gate `skipPerceptionChecking` behind `#if DEBUG` via a shared helper
- apply the debug-only suppression to both `readState` and child-wrapper
`access(...)`
- add `test_nativeOptionalChildStoreObservation` so native observation
covers the wrapper path through `Store.access(...)`
- include the updated `Samples/Tuist/Package.resolved`

## Why
Perception only consults `skipPerceptionChecking` from its debug-only
checking path, so release builds do not need the TaskLocal wrapper. The
new native optional-wrapper test closes the coverage gap in the path
that motivated the original suppression.

## Test plan
- [x] Ensure the new test passes
- [x] Look for regressions on the `ObservableComposition` app.

Co-authored-by: Codex <codex@openai.com>
johnnewman-square added a commit that referenced this pull request Jul 16, 2026
PRs #389 and #390 automatically suppressed Perception runtime warnings
on platforms using native Observation. This restores the warnings by
default while preserving an opt-in suppression path.

## Summary

- Add
`Runtime.Configuration.suppressPerceptionCheckingWhenUsingObservation`,
defaulting to `false`
- Continue normal Store access unless suppression is explicitly enabled
- Apply suppression only in debug builds on iOS 17+, macOS 14+, tvOS
17+, and watchOS 10+
- Cover both direct state reads and child Store wrapper access
- Add tests for the default warning behavior and opt-in suppression

## Test plan

- [x] Run `StoreTests` on iOS 17.5 — 25 passed
- [x] Run `StoreTests` on iOS 16.2 — passed with 8 expected skips
- [x] Run the ObservableComposition sample app on iOS 17 to ensure the
warnings are occurring by default.

## Checklist

- [x] Unit Tests
- [x] UI Tests (not applicable)
- [x] Snapshot Tests (not applicable)
- [x] I have made corresponding changes to the documentation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants