В этом случае @State
ведет себя точно так же, как и положено: как постоянное хранилище для компонента, к которому он прикреплен.
По сути, отправка представления с помощью NavigationLink аналогична любому другому компоненту в иерархии представлений. Виден ли экран на самом деле - это деталь реализации. Хотя SwiftUI на самом деле не отображает скрытые элементы пользовательского интерфейса после закрытия экрана, он сохраняет View
дерево.
Вы можете заставить представление быть полностью отброшенным с помощью модификатора .id(_:)
, например:
struct ContentView: View {
@State var i = 0
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: DetailView().id(i)) {
Text("Show Detail View")
}
Button("Toggle") {
self.i += 1
UserDefaults.standard.set(
!UserDefaults.standard.bool(forKey: "JustKey"),
forKey: "JustKey")
}
}
}
}
}
Кнопка переключения изменяет значение JustKey и увеличивает значение, которое мы передаем в .id(i)
. Когда единственный аргумент id(_:)
изменяется, модификатор id сообщает SwiftUI, что это другое представление, поэтому, когда SwiftUI запускает свой алгоритм сравнения, он отбрасывает старый и создает новый (с новыми @State
переменными). Подробнее о id см. здесь.
Приведенное выше объяснение дает обходной путь, но это не очень хорошее решение, ИМО. Гораздо лучшее решение - использовать ObservableObject
. Это выглядит так:
@ObservedObject condition = KeyPathObserver(\.JustKey, on: UserDefaults.standard)
Вы можете найти код, реализующий KeyPathObserver
и полный пример рабочей площадки, в этом SO-ответе
19.12.2019