Skip to content

fix(ios): use positional index for SwiftUI TabView tags#1082

Merged
troZee merged 1 commit into
callstack:masterfrom
ios-youngsun-ban:fix/ios-pagerview-duplicate-tag
Jul 3, 2026
Merged

fix(ios): use positional index for SwiftUI TabView tags#1082
troZee merged 1 commit into
callstack:masterfrom
ios-youngsun-ban:fix/ios-pagerview-duplicate-tag

Conversation

@ios-youngsun-ban

Copy link
Copy Markdown
Contributor

Summary

Fixes #1079.

In the new SwiftUI TabView-based iOS implementation (ios/PagerView.swift),
the tag for each page is derived with props.children.firstIndex(of:) while
iterating that same array inside ForEach:

ForEach(props.children) { child in
  if let index = props.children.firstIndex(of: child) {
    RepresentableView(view: child.view).tag(index)
  }
}

firstIndex(of:) returns the index of the first Equatable-equal element,
so equal entries resolve to the same index and produce duplicate .tag
values. With TabView(selection:), duplicate tags break page selection — and
on iOS 17 and below this surfaces as a hard crash
(NSInternalInconsistencyException)
. The lookup is also O(n²) over the
ForEach.

This PR derives the tag from the positional index via enumerated() (unique by
construction) while keeping stable SwiftUI identity through the element id:

ForEach(Array(props.children.enumerated()), id: \.element.id) { index, child in
  RepresentableView(view: child.view).tag(index)
}

Impact: iOS new-architecture (Fabric) implementation only. Identity diffing is
unchanged (still keyed by IdentifiablePlatformView.id); the change only makes
the tag unique by construction, removing the crash and the O(n²) lookup.

Test Plan

Verified on a device and a simulator running iOS 17 (and below): before this
change, paging throws NSInternalInconsistencyException and crashes; after
applying the patch the crash is gone and paging works as expected. Behavior is
otherwise unchanged — the positional index matches the previous firstIndex
result in normal states.

What's required for testing (prerequisites)?

  • iOS example app on the new architecture (Fabric), running on iOS 17 or below.

What are the steps to reproduce (after prerequisites)?

  • Render <PagerView> with multiple children and swipe / change pages.
    Before the fix this crashes with NSInternalInconsistencyException on iOS ≤ 17;
    after the fix paging works normally.

Compatibility

OS Implemented
iOS
Android

Checklist

  • I have tested this on a device and a simulator
  • I added the documentation in README.md
  • I updated the typed files (TS and Flow)

@ios-youngsun-ban ios-youngsun-ban changed the title fix(ios): use positional index for SwiftUI TabView tags (closes #1079) fix(ios): use positional index for SwiftUI TabView tags Jun 8, 2026
@troZee troZee requested a review from Copilot July 3, 2026 20:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Fixes an iOS SwiftUI TabView(selection:) crash/wrong-selection scenario in the new-architecture PagerView implementation by ensuring each page’s .tag is unique and derived from position (not Equatable equality).

Changes:

  • Replace firstIndex(of:) (O(n²) and can yield duplicate indices) with positional indices via enumerated().
  • Preserve SwiftUI identity diffing by keeping the ForEach identity keyed on child.id (IdentifiablePlatformView.id).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@troZee troZee merged commit 9f5e139 into callstack:master Jul 3, 2026
2 checks passed
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.

[iOS] New Arch PagerView (SwiftUI TabView): firstIndex(of:) yields duplicate .tag → crash / wrong page

3 participants