当两个导航堆栈之间切换时,就会发生问题。我没有简单地解雇和去灭绝以前的视图模型,而是看到了视图模型初始化/去启动和视图外观/消失的多个实例。
有人知道为什么会发生这种情况以及如何预防?
struct MainView: View {
enum Destination: Hashable {
case second
}
@State var isThirdPresented: Bool = false
@State var path: NavigationPath = .init()
var body: some View {
if isThirdPresented {
NavigationStack {
ContentView(identifier: "3️⃣") { }
}
} else {
NavigationStack(path: $path) {
ContentView(identifier: "1️⃣") {
path.append(Destination.second)
}
.navigationDestination(for: Destination.self) { destination in
switch destination {
case .second:
ContentView(identifier: "2️⃣") {
isThirdPresented.toggle()
}
}
}
}
}
}
}
struct ContentView: View {
@Observable class ViewModel {
let identifier: String
init(identifier: String) {
self.identifier = identifier
print("\(identifier) view model initialized")
}
deinit {
print("\(identifier) view model deinitialized")
}
}
@State var viewModel: ViewModel
let action: () -> Void
init(identifier: String, action: @escaping () -> Void) {
viewModel = .init(identifier: identifier)
self.action = action
}
var body: some View {
VStack {
Text("View \(viewModel.identifier)")
Button("Action", action: action)
}
.onAppear { print("\(viewModel.identifier) appeared") }
.onDisappear { print("\(viewModel.identifier) disappeared") }
}
}
直到现在,我从未在A内看到一个可观察到的课程,这也许就是为什么我发现整个设置非常扭曲的原因。
如果“可观察到的”View
在一个结构内部,谁会/什么要观察?
,然后是所有
ViewModel
View
的问题,并绕过“相同的“视图”传递不同的
弦“标识符”。正如其他人提到的评论,您实际上永远不会回到同一视图,因为您每次都会创建一个新实例。如果您有一个既定的流程,则应拥有支持它的模型。 ,例如,您可以为各种可能的身份案例提供一个
init
枚枚举,而对于每种情况,则可以枚举一个相关的路线。因此,如果用户状态为
deinit
,则在其中定义了下一步/下一步的逻辑:
ContentView
可以通过各种选项(例如每种情况的颜色)进一步增强相同的枚举;
Auhorization
迫使强迫相同的expired
支持所有这些情况,具有专用视图将更简单,更灵活。也许不是所有情况下,但是例如,auth错误可能会转到一个。否则,您的
enum Authorization: String {
case authorized, denied, locked, expired, guest
var route: DestinationRoute {
switch self {
case .authorized: .home
case .denied: .error
case .locked: .error
case .expired: .error
case .guest: .authorization
}
}
}
会很快变得凌乱。
为了观察,您可以使用单身人士
var color: Color {
switch self {
case .authorized: .green
case .denied: .red
case .locked: .pink
case .expired: .gray
case .guest: .orange
}
}
可以从任何视图访问的类,也可以使用必须通过
ContentView
通过的非单身子。在此示例中,我使用单例来简单。
ErrorView
就像此一样,您可以使用ContentView
从任何视图访问或修改用户状态。或者,将其分配给视图属性:
@Observable
可观察到的导航的想法,该导航使导航路径可从任何视图或任何功能(包括environment
类)都能访问和修改,该函数可以在用户状态更改时触发导航的选项。
//Authorization observable singleton
@Observable class UserAuthorization {
var status: Authorization = .guest
var navigateOnStatusChange = false
static let service = UserAuthorization() // <- the singleton
private init() {}
func setAuthStatus(_ status: Authorization) {
self.status = status
if navigateOnStatusChange {
Navigator.nav.path.append(self.status.route)
}
}
}
这里是将所有这些放在一起的完整代码:
UserAuthorization.service.status