在父 swiftui 视图中,我怎么知道内部视图 viewmodel void 方法中的状态何时发生变化?

In parent swiftui view how could I know when a state changes in an inner views viewmodel void method?

给定一个 AuthenticationView swiftui 结构包含一个 UserLoginView。 UserLoginView 有一个 UserLoginViewModel class 用于处理登录按钮操作。

在 AuthenticationView 中,我想知道内部 UserLoginView 中的变量值何时发生变化(如果 tutorialScreenIsShowable 在 AuthenticationView 中为真,NavigationLink 导航到下一张幻灯片)。

struct AuthenticationView: View {
    @State private var tutorialScreenIsShowable = false
    var body: some View {
        NavigationView {
            ZStack {
                NavigationLink(destination: TutorialView(), isActive: $tutorialScreenIsShowable) {
                    EmptyView()
                }
                UserLoginView(tutorialScreenIsShowable: self.$tutorialScreenIsShowable)
            }
        }
    }
}

,

struct UserLoginView: View {
    @Binding var tutorialScreenIsShowable: Bool
    @ObservedObject var userLoginViewModel = UserLoginViewModel()
    var body: some View {
        Button(action: {
            self.userLoginViewModel.loginButtonAction() // it not works but I need this way
//            self.tutorialScreenIsShowable = self.userLoginViewModel.loginButtonActionWithReturn() // it works, but its not good in this case
        }) {
            Text("Log in")
        }
    }
}

,

class UserLoginViewModel: NSObject, ObservableObject {
    @Published var tutorialScreenIsShowable = false
    
    func loginButtonAction() {
        self.tutorialScreenIsShowable = true
    }
    
    func loginButtonActionWithReturn() -> Bool {
        return true
    }
}

据我所知,如果函数有一个可以工作的 return 值,但在这种情况下,有一个委托方法 运行 我可以在其中处理变量。

我想尽可能避免@EnvironmentObject,我希望有另一个解决方案。

你能帮我解决这个问题吗?

编辑:我简化了示例。并在此处上传示例项目:https://www.dropbox.com/s/paosp6iom9oks9p/InnerViewPropBind.zip

此行为的起源是 NavigationView 在更新期间多次重新创建自己的内容。

这是一个可能的解决方案 - 一些重新设计和所有权变更。

测试 Xcode 11.4 / iOS 13.4

struct AuthenticationView: View {
    // keep model here to avoid recreation inside navigation view
    @ObservedObject var userLoginViewModel = UserLoginViewModel()

    var body: some View {
        NavigationView {
            ZStack {
                // use binding directly in view model
                NavigationLink(destination: Text("TutorialView"), isActive: $userLoginViewModel.tutorialScreenIsShowable) {
                    EmptyView()
                }

                UserLoginView(userLoginViewModel: userLoginViewModel)
            }
        }
    }
}

struct UserLoginView: View {
    @ObservedObject var userLoginViewModel: UserLoginViewModel
    var body: some View {
        Button(action: {
            self.userLoginViewModel.loginButtonAction()
        }) {
            Text("Log in")
        }
    }
}

class UserLoginViewModel: NSObject, ObservableObject {
    @Published var tutorialScreenIsShowable = false

    func loginButtonAction() {
        self.tutorialScreenIsShowable = true
    }

    func loginButtonActionWithReturn() -> Bool {
        return true
    }
}