gpt4 book ai didi

直接设置选择而不是从 viewModel 设置选择时,SwiftUI NavigationLink 行为不同

转载 作者:行者123 更新时间:2023-12-04 08:31:56 24 4
gpt4 key购买 nike

我一直在使用 SwiftUI 并遇到了意外的行为。
我有 View A 和 View B 和 View C。 View C 具有从 View A 更改 AppState 的 EnviromentObject
View B 具有带有选择的 ViewModel
如果我从 ViewModel 调用函数来更改选择,那么
View C 显示几秒钟,然后它自动弹回 View B
如果我直接从 View B(而不是 View 模型)更改选择,一切都会按预期工作。
另外,如果我注释掉Dissapear,它也可以工作。但是,当屏幕消失时,我需要更改 environmentObject
这是 View B 和 View 模型

import SwiftUI

class AppState: ObservableObject {
@Published
var shouldHideUserInfo = false
}


struct ContentView: View {

@EnvironmentObject
var appState: AppState

@State
var selection: Int? = nil

var body: some View {
NavigationView {
VStack {
if !appState.shouldHideUserInfo {
Text("USER INFO")
}

NavigationLink(
destination: ViewA(),
tag: 1,
selection: $selection,
label: { EmptyView()})

Button("MOVE TO VIEW A") {
selection = 1
}
}
}
}
}


class ViewAModel: ObservableObject {
@Published
var selection: Int? = nil

func navigate() {
selection = 2 //<- this doesnt
}
}

struct ViewA: View {

@ObservedObject
var viewModel: ViewAModel

init() {
viewModel = ViewAModel()
}

@State
var selection: Int? = nil //<- this works

var body: some View {
VStack
{
Text("VIEW A")

NavigationLink(
destination: ViewB(),
tag: 2,
selection: $viewModel.selection,
label: { EmptyView()})

Button("MOVE TO VIEW B") {
//selection = 2 <-- this works
viewModel.navigate() //<- this doesnt
}

}
}
}

struct ViewB: View {

@EnvironmentObject
var appState: AppState

@State
var selection: Int? = nil

var body: some View {
VStack
{
Text("VIEW B")

}
.onAppear {
appState.shouldHideUserInfo = true
}
}
}
工厂模式没有解决问题:
    static func makeViewA(param: Int?) -> some View {
let viewModel = ViewAModel(param: param)
return ViewA(viewModel: viewModel)
}
}

最佳答案

我明白了……这与帖子中的有点不同。问题是因为 View 模型被重新创建(这是长期观察到的 NavigationView 行为),因此绑定(bind)丢失。
快速修复是

struct ViewA: View {

@StateObject
var viewModel: ViewAModel = ViewAModel()

init() {
// viewModel = ViewAModel()
}

// ... other code
}
替代方法是将 View 模型的所有权保留在 ViewA 之外.
更新:SwiftUI 1.0 兼容 - 这是一种适用于任何地方的变体。问题的原因在 AppState . ViewB中的代码更新 appState
.onAppear {
appState.shouldHideUserInfo = true
}
这会导致 ContentView 的重建 body ,它重新创建 ViewA , 重新创建 NavigationLink ,它会删除先前的链接和 ViewB关门了。
为了防止这种情况,我们需要避免重建 ViewA .这可以通过制作 ViewA 来完成。是一个 Equatable ,所以 SwiftUI 检查是否 ViewA需要重新创建,我们将回答 NO。
这是怎么回事:
NavigationLink(
destination: ViewA().equatable(), // << here !!
tag: 1,
selection: $selection,
label: { EmptyView()})
struct ViewA: View, Equatable {
static func == (lhs: ViewA, rhs: ViewA) -> Bool {
true
}

// .. other code

关于直接设置选择而不是从 viewModel 设置选择时,SwiftUI NavigationLink 行为不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64976246/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com