Post

Debug Repaints with Flash Updated Regions in Xcode 26

See real-time view re-renders with Xcode 26's Flash Updated Regions and eliminate unnecessary updates.

Debug Repaints with Flash Updated Regions in Xcode 26

Xcode 26 exposes Flash Updated Regions directly in the debugger so you can see exactly which parts of your UI redraw each frame.

Enable It

Run your app on device or Simulator, then: Debug ▸ View Debugging ▸ Rendering ▸ Flash Updated Regions

Yellow flashes indicate repaints.

Notes:

  • This visualization has existed in Instruments and Simulator color overlays for years; Xcode 26 puts it in the main Debug menu.
  • Simulator also offers color overlays from its own Debug menu.

What It Shows

Flash Updated Regions highlights screen areas that actually update each frame. Use it to confirm state changes only repaint the views you expect.

SwiftUI Example: Stop Unnecessary Repaints

Problem: A parent timer triggers recomputation that needlessly touches child rows.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import SwiftUI
import Combine

struct ContentView: View {
    @State private var tick = 0
    private let items = Array(0..<200)

    var body: some View {
        VStack {
            // Unaffected list should not repaint each second
            StaticList(items: items)

            Text("Tick: \(tick)")
                .monospaced()
                .padding(.top, 8)
        }
        .task {
            // Drive a change every second
            let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
            for await _ in timer.values { tick &+= 1 }
        }
    }
}

struct StaticList: View, Equatable {
    let items: [Int]
    static func == (lhs: StaticList, rhs: StaticList) -> Bool { 
        lhs.items == rhs.items 
    }

    var body: some View {
        List(items, id: \.self) { i in
            Row(i: i)
        }
        // Prevent body updates when `items` hasn't changed
        .equatable()
    }
}

struct Row: View {
    let i: Int
    var body: some View { Text("Row \(i)") }
}

How to use the overlay: Turn on Flash Updated Regions and watch the list area. With .equatable() applied to StaticList, it should remain quiet while only the Text flashes once per second.

When to Use

  • Scrolling lists that stutter after adding state
  • Complex compositions where a minor state change causes large yellow areas
  • Verifying refactors like extracting subviews, adding .equatable(), or moving state into @StateObject

☕ Support My Work

If you found this post helpful and want to support more content like this, you can buy me a coffee!

Your support helps me continue creating useful articles and tips for fellow developers. Thank you! 🙏

This post is licensed under CC BY 4.0 by the author.