Why does ForEach initialize its Child View twice as much in SwiftUI?
Asked Answered
S

0

11

I came across a weird behaviour of SwiftUI's ForEach view.

I've noticed that ForEach always initialize its child view twice as much as it should according to its repetition. Normally, when you render the view, its init is called once. But if you put the view inside ForEach and loop it 4 times, the child view is initialized 8 times instead of 4.

Is this a desired behavour or am I missing something?

You can test it using the simple code below.

tested on: Xcode 14.0.1, iOS 16, simulator iPhone 13 Pro (with iOS 16)

I am grateful for any feedback!

struct ContentView: View {
    
    var body: some View {
        VStack {
            // Note that ForEach is looped 4 times!
            ForEach(0..<4, id: \.self) { _ in
                CustomView() // -> this view is initialized 8 times instead of 4.
            }
        }
    }
}

struct CustomView: View {

    // custom initializer with print to check how many times this view is initialized in log output
    init() {
        print("CustomView initialized")
    }
    
    var body: some View {
        Text("Some Custom View")
    }
}
Spruik answered 19/10, 2022 at 2:12 Comment(3)
Ranges are unsafe with SwiftUI for this reason, they don’t preserve identity. Watch Demystify SwiftUI from one of the WWDCsMantua
Yes, I am aware of the drawbacks of using ranges in ForEach. But that is not the case of duplicate initialization. Even if you use an array of objects with id property, the problem still persists. The child view is still initialized twice as much as it should be.Spruik
I downloaded the old Xcode 13.4.1 that has iOS simulator 15.5 and it didn't have this problem. Seems like a major bug to me, I think we should report feedback on this.Smitty

© 2022 - 2024 — McMap. All rights reserved.