swiftui · note · identity

ForEach Identity Debug Checklist

Published March 31, 2026 · 2 min read · intermediate

Context

When ForEach identity is unstable, SwiftUI updates still compile but behavior degrades: rows reset, animations snap, and state appears to jump between items.


The snippet

ForEach(items.indices, id: \.self) { index in
    ItemRow(item: items[index])
}

Why this works

This pattern only works safely for fully static collections. As soon as you reorder, filter, insert, or delete, index identity no longer represents logical item identity.

Use this checklist:

  • Does each model have one stable ID from data creation?
  • Is ForEach keyed by that model ID, not index?
  • Are IDs preserved across fetch/merge steps?
  • Are you accidentally recreating IDs in mappers?

If any answer is “no”, fix identity before debugging animation or state wrappers.


Use it when…

  • list rows reset unexpectedly after updates
  • row-level controls keep wrong state after sorting/filtering
  • insert/delete animations feel like full row replacement

Avoid it when…

  • collection is static and identity churn is impossible
  • you already have stable Identifiable models and deterministic transforms
  • the bug is clearly ownership-related rather than list reconciliation

Takeaway: Debug list behavior by validating identity first, then state ownership.

Next steps

If you want the deeper model behind this checklist, continue with: