Logo for tanaschita.com

Understanding structural identity in SwiftUI

Learn how SwiftUI optimizes UI updates.

10 Mar 2025 · 3 min read

Unlike traditional UI frameworks where we manually track and update UI elements, SwiftUI automatically refreshes views when state changes. However, redrawing everything would be inefficient. This is where structural identity comes in - it allows SwiftUI to determine which views actually need to be redrawn, optimizing performance.

Let's jump in and look at how this works.

Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE

What is structural identity?

When a state change occurs in SwiftUI, the framework reconstructs the entire view hierarchy. This might sound inefficient at first, but it's actually remarkably optimized, because SwiftUI views are lightweight value types (structs) and most importantly, because SwiftUI uses structural identity to avoid unneeded redrawings.

Structural identity is SwiftUI's way of recognizing whether a view before and after a state change is fundamentally the same view. When SwiftUI identifies views as structurally identical, it preserves their state and redraws only the parts that have changed.

A view's structural identity is determined by:

  • Its type
  • Its position in the view hierarchy
  • The identity of its ancestors

Update vs. redraw in SwiftUI

While the terms update and redraw may sound interchangeably, they refer to different processes:

  • Update: SwiftUI reinitializes the view evaluating the body property, while preserving state. This happens every time a state change occurs.
  • Redraw: This is when SwiftUI sends rendering instructions to the GPU, updating the pixels on the screen. Just because a view is reinitialized doesn't mean it will be redrawn.

Structural identity in action

Consider this example:

struct ExampleView: View {
@State private var isOn = true
var body: some View {
VStack {
Text("Is on: \(isOn ? "yes": "no")")
Button("Switch") {
isOn.toggle()
}
if (isOn) {
BottomViewOn()
} else {
BottomViewOff()
}
}
}
}

When a user taps the "Switch" button:

  1. The isOn state variable changes.
  2. SwiftUI rebuilds the view hierarchy. That means ExampleView is reinitialized, and SwiftUI preserves the state isOn.
  3. Using structural identity, SwiftUI recognizes that Text and Button are fundamentally the same views as before.
  4. Since the Text view's content has changed, it gets redrawn.
  5. The Button view remains untouched because its content and structure haven't changed.
  6. What happens with BottomViewOn and BottomViewOff? When isOn changes, one view is removed from the hierarchy, and the other one is newly created. And any internal state within BottomViewOn or BottomViewOff is lost when switching between them.

How to persist state across both views?

If we want to keep state in BottomViewOn and BottomViewOff, we could:

  • Extract their state to the parent view e.i. manage it externally or
  • Use structural identity by making the following changes:
ZStack {
BottomViewOn()
.opacity(isOn ? 1 : 0)
.accessibilityHidden(!isOn)
BottomViewOff()
.opacity(isOn ? 0 : 1)
.accessibilityHidden(isOn)
}

Instead using an if-else condition, we now keep both views in the hierarchy preserving structural identity.

Structural identity in lists

In SwiftUI, structural identity also plays an important role in lists. When using a List view, SwiftUI requires each item to have a unique identifier, either by conforming to Identifiable or by specifying an id key path. This allows SwiftUI to track individual items even when their order changes, preventing unnecessary redraws. Using unique IDs such as database IDs is a good practice because relying on indices or non-unique properties can lead to incorrect updates, glitches, or unexpected UI behavior when modifying the list dynamically.

SwiftUI as a black box

SwiftUI hides much of its inner workings, making it feel like a black box. SwiftUI decides what to update and redraw behind the scenes, so we can only experiment to understand its behavior. Many hope SwiftUI will be open-sourced someday, giving us a clearer look inside.

Sponsorship logo
Preparing for a technical iOS job interview
Preparing for a technical iOS Job Interview with over 300 questions & answers. Covering Swift & Objective-C, SwiftUI & UIKit, Combine, HTTP Networking, iOS File System, Core Data, Concurrency with async/await, Security, Automated Testing, Dependency Management, AI & Machine Learning and more.
LEARN MORE
Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE
Sponsorship logo
Become a sponsor of tanaschita.com
By publishing an article on different iOS topics every week, tanaschita.com is constantly growing in the developer community and may provide a great audience for you as a sponsor.
CLICK TO LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

swiftui

swift

concurrency

async/await

ios

Building responsive and reliable search in SwiftUI

Learn how to debounce search input, cancel obsolete requests and prevent stale results using Swift concurrency.

14 Sep 2026 · 6 min read

Latest articles and tips

© 2026 tanaschita.com

Privacy policy

Impressum