0

My goal is to pass values between views, from Chooser to ThemeEditor. When the user presses an icon, I'm saving the object that I want to pass and later, using sheet and passing the newly created view with the content of the @State var.

The assignment is done successfully to the @State var themeToEdit, however it is nil when the ThemeEditor view is created in the sheet

What am I doing wrong?

struct Chooser: View {
    @EnvironmentObject var store: Store
    
    @State private var showThemeEditor = false
    @State private var themeToEdit: ThemeContent?
    @State private var editMode: EditMode = .inactive
    @State private var isValid = false
    
    var body: some View {
        
        NavigationView {
            List {
                ForEach(self.store.games) { game in
                    NavigationLink(destination: gameView(game))
                    {
                        Image(systemName: "wrench.fill")
                            .imageScale(.large)
                            .opacity(editMode.isEditing ? 1 : 0)
                            .onTapGesture {
                                self.showThemeEditor = true
                                /* themeInfo is of type struct ThemeContent: Codable, Hashable, Identifiable */
                                self.themeToEdit = game.themeInfo 
                            }
                        VStack (alignment: .leading) {
                            Text(self.store.name(for: something))
                                
                            HStack{
                                /* some stuff */
                                Text(" of: ")
                                Text("Interesting info")
                            }
                        }
                    }
                }
                .sheet(isPresented: $showThemeEditor) {
                    if self.themeToEdit != nil { /* << themeToEdit is nil here - always */
                        ThemeEditor(forTheme: self.themeToEdit!, $isValid)
                    } 
                }
            }
            .environment(\.editMode, $editMode)
        }
    }
}


struct ThemeEditor: View {
    @State private var newTheme: ThemeContent
    @Binding var isValid: Bool
    @State private var themeName = ""
    
    init(forTheme theme: ThemeContent, isValid: Binding<Bool>) {
        self._newTheme = State(wrappedValue: theme)
        self._validThemeEdited = isValid
    }
    var body: some View {
           ....
    }
}

struct ThemeContent: Codable, Hashable, Identifiable {
/* stores simple typed variables of information */
}
Shaihi
  • 3,952
  • 4
  • 27
  • 47

2 Answers2

1

The .sheet content view is captured at the moment of creation, so if you want to check something inside, you need to use .sheet(item:) variant, like

.sheet(item: self.$themeToEdit) { item in
    if item != nil {
        ThemeEditor(forTheme: item!, $isValid)
    } 
}

Note: it is not clear what is ThemeContent, but it might be needed to conform it to additional protocols.

Shaihi
  • 3,952
  • 4
  • 27
  • 47
Asperi
  • 228,894
  • 20
  • 464
  • 690
1

Use Binding. Change your ThemeEditor view with this.

struct ThemeEditor: View {
    @Binding private var newTheme: ThemeContent?
    @Binding var isValid: Bool
    @State private var themeName = ""
    
    init(forTheme theme: Binding<ThemeContent?>, isValid: Binding<Bool>) {
        self._newTheme = theme
        self._isValid = isValid
    }
    var body: some View {
        ....
    }
}

And for sheet code

.sheet(isPresented: $showThemeEditor) {
    ThemeEditor(forTheme: $themeToEdit, isValid: $isValid)
}

On Action

.onTapGesture {
    /* themeInfo is of type struct ThemeContent: Codable, Hashable, Identifiable */
    self.themeToEdit = game.themeInfo
    self.showThemeEditor = true
    
}
Raja Kishan
  • 16,767
  • 2
  • 26
  • 52
  • Thanks - I accepted @Asperi's answer since it explained what was happening and why I was getting unexpected behavior. Since I'm starting with SwiftUI I prefer that as an answer rather than a workable workaround. – Shaihi Jan 18 '21 at 12:18
  • 1
    yes, I agree but please note. this not a workaround answer. – Raja Kishan Jan 18 '21 at 12:20