我相信这与以下内容相关但不完全相同:
- 与新的导航堆栈结合时发现 @State 的奇怪行为 - 这是一个错误还是我做错了? https://stackoverflow.com/questions/73885353/found-a-strange-behaviour-of-state-when-combined-to-the-new-navigation-stack/
The Navigation
api 似乎优先考虑效率(初始化很昂贵)并且屏幕上必须始终显示某些内容。它似乎不会取消初始化已经消失的视图,直到它初始化并出现替换视图。
这可能会导致内存泄漏(我相信 https://developer.apple.com/forums/thread/716804)如果你尝试管理Navigation
框架视图具有导航框架之外的内容,但只要Navigation
框架仍然负责,事情最终将被取消,但直到新视图被初始化。
新版本
此版本使用一个协调器,但保留初始与主应用程序路径的单独枚举和视图。
import Foundation
import SwiftUI
enum AppSceneTvTe:Hashable {
case setup
case app
}
enum PathTvTeOptions: Hashable {
case optionA(OptionAVM)
case optionB(OptionBVM)
}
struct SplashTVTEView: View {
@StateObject var oneCoordinator = CoordinatorTvTe()
var body: some View {
NavigationStack(path: $oneCoordinator.path) {
splash
.navigationDestination(for: AppSceneTvTe.self) { scene in
switch scene {
case .app:
SplashTvTeAppRootView().environmentObject(oneCoordinator)
default:
splash
}
}
}
}
var splash: some View {
VStack {
Text("Splash Page")
Button(action:navigateToApp) {
Text("Go App Root")
}
}.navigationBarBackButtonHidden(true)
}
func navigateToApp() {
oneCoordinator.showStack()
}
}
final class CoordinatorTvTe: ObservableObject {
@Published var path = NavigationPath()
func showA() {
path.append(PathTvTeOptions.optionA(OptionAVM()))
}
func showB() {
path.append(PathTvTeOptions.optionB(OptionBVM()))
}
func showInitial() {
unwindAll()
//path = NavigationPath()
}
func showStack() {
path = NavigationPath()
path.append(AppSceneTvTe.app)
}
func unwindAll() {
while !path.isEmpty {
path.removeLast()
}
}
}
struct SplashTvTeAppRootView: View {
@EnvironmentObject var navigation: CoordinatorTvTe
var body: some View {
VStack {
Text("Real Root")
}
.navigationBarBackButtonHidden(true)
.toolbar {
Button(action: self.navigation.showA) {
Text("Push A")
}
}
.navigationDestination(for: PathTvTeOptions.self) { path in
switch path {
case .optionA(let vm):
OptionAView(vm: vm)
.toolbar {
Button(action: self.navigation.showB) {
Text("Push B")
}
}
case .optionB(let vm):
OptionBView(vm: vm)
.toolbar {
Button(action: self.navigation.showInitial) {
Text("Show Initial")
}
}
}
}
}
}
旧版本
目前解决这个问题的方法是将其全部保留在导航堆栈中,这样就没有单独的场景与路径。
此代码使用布尔值来控制初始屏幕,但它可能是路径选项之一 - 这是注释掉的代码。
编辑添加:当您尝试使初始状态为真时,用完布尔解决方案会变得很奇怪。堆栈一直获胜,所以我把它拿出来了。
enum Path: Hashable {
case initial
case a(StoreA)
case b(StoreB)
}
final class CoordinatorStore: ObservableObject {
@Published var path: [Path] = [.initial]
func showA() {
let store = StoreA()
path.append(.a(store))
}
func showB() {
let store = StoreB()
path.append(.b(store))
}
func showInitial() {
path = []
path.append(.inital)
}
func showStack() {
path = []
}
}
struct Coordinator: View {
@ObservedObject var store: CoordinatorStore
var body: some View {
NavigationStack(path: $store.path) {
VStack {
Text("Real Root")
}
.toolbar {
Button(action: self.store.showA) {
Text("Push A")
}
}
.navigationDestination(for: Path.self) { path in
switch path {
case .a(let store):
ViewA(store: store)
.toolbar {
Button(action: self.store.showB) {
Text("Push B")
}
}
case .b(let store):
ViewB(store: store)
.toolbar {
Button(action: self.store.showInitial) {
Text("Show Initial")
}
}
case .initial:
initial
}
}
}
}
var initial: some View {
VStack {
Text("Initial")
Button(action: store.showStack) {
Text("Go to Stack")
}
}.navigationBarBackButtonHidden(true)
}
}