Why does state reset to nil after assignment

Viewed 637

In a simple SwiftUI app, I am experimenting with showing a sheet when clicking on a row in a list. When the sheet opens, a state variable has been assigned with the list object that was clicked on. See code below.

For some unknown reason the state variable is nil, when the sheets open?

Did I misunderstand something with SwiftUI or forgot something concerning state variables. I hope someone will enlighten me.


import SwiftUI

struct ContentView: View {
    
    class Object: Identifiable {
        let id: String
        init(_ id: String) { self.id = id }
    }
    
    let collection = [Object("1"),Object("2"),Object("3")]
    
    @State var show = false
    @State var state: Object?
    
    var body: some View {
        
        List(collection) { item in
            
            HStack{ Text(item.id); Spacer() }
                .background(Color.white)
                .onTapGesture(count:1, perform: {
                    self.state = item
                    show.toggle()
            })
        }
        .sheet(isPresented:$show) {
            if state == nil {
                Text("Error state == nil ?")
            }
            else {
                Text(state!.id)
            }
        }
    }
}

1 Answers

The issue is due to sheet is created before button clicked. The solution for your scenario is to use .sheet(item: approach.

Here is corrected code. Tested with Xcode 12.1 / iOS 14.1

struct ContentView: View {
    
    class Object: Identifiable {
        let id: String
        init(_ id: String) { self.id = id }
    }
    
    let collection = [Object("1"),Object("2"),Object("3")]
    
    @State var state: Object?
    
    var body: some View {
        
        List(collection) { item in
            
            HStack{ Text(item.id); Spacer() }
                .background(Color.white)
                .onTapGesture(count:1, perform: {
                    self.state = item
            })
        }
        .sheet(item: $state) { item in
                 Text(item.id)
        }
    }
}
Related