@State var не сохраняет значение

#swiftui #swiftui-state

#swiftui #swiftui-состояние

Вопрос:

Моя цель — передавать значения между представлениями, от Chooser к ThemeEditor. Когда пользователь нажимает значок, я сохраняю объект, который хочу передать, и позже, используя sheet и передавая вновь созданное представление с содержимым @State var .

Присвоение выполняется успешно @State var themeToEdit , однако это происходит nil при создании ThemeEditor представления в sheet

Что я делаю не так?

 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 */
}
 

Ответ №1:

Представление .sheet содержимого фиксируется в момент создания, поэтому, если вы хотите что-то проверить внутри, вам нужно использовать .sheet(item:) variant, например

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

Примечание: неясно, что это ThemeContent такое, но это может потребоваться для соответствия дополнительным протоколам.

Ответ №2:

Использовать Binding . Измените представление редактора темы с помощью этого.

 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 {
        ....
    }
}

 

И для кода листа

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

При действии

 .onTapGesture {
    /* themeInfo is of type struct ThemeContent: Codable, Hashable, Identifiable */
    self.themeToEdit = game.themeInfo
    self.showThemeEditor = true
    
}
 

Комментарии:

1. Спасибо — я принял ответ @Asperi, поскольку он объяснил, что происходит и почему я получаю неожиданное поведение. Поскольку я начинаю с SwiftUI, я предпочитаю это как ответ, а не как работоспособный обходной путь.

2. да, я согласен, но, пожалуйста, обратите внимание. это не обходной ответ.