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

Posted

技术标签:

【中文标题】在父 swiftui 视图中,我如何知道内部视图 viewmodel void 方法中的状态何时发生变化?【英文标题】:In parent swiftui view how could I know when a state changes in an inner views viewmodel void method? 【发布时间】:2020-08-27 07:18:22 【问题描述】:

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

在 AuthenticationView 中,我想知道内部 UserLoginView 中变量的值何时发生变化(如果 AuthenticationView 中的 tutorialScreenIsShowable 为 true,则 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
    

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

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

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

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

【问题讨论】:

【参考方案1】:

这种行为起源于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
    

【讨论】:

感谢您的建议,但不幸的是它不起作用。 ): NavigationLink 不会导航到下一张幻灯片。 嗯,导航是不同的问题。您无法在模态视图中导航,首先您必须关闭模态视图。 如果 loginWithGoogleButtonAction 有返回值 (self.tutorialScreenIsShowable = self.userLoginViewModel.loginWithGoogleButtonAction() ),则导航有效。所以这可能不是问题。否则,我也尝试通过属性控制视图的可见性,但它也没有改变。 是否收到didSignInFor 回调?在主队列上?如果第一次是,但第二次没有,则应将重定向添加到主调度队列。我无法测试您的 API 相关部分。 请再次查看示例,我清除了代码,现在没有api。我链接了我的示例项目。我希望它可以更清洁。谢谢!!

以上是关于在父 swiftui 视图中,我如何知道内部视图 viewmodel void 方法中的状态何时发生变化?的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI MVVM 中的子视图和父视图之间共享值

SwiftUI 视图 onAppear 事件调用回扫手势动作

如何从内部的 SwiftUI 视图返回到 UIKit?

SwiftUI - 更新父视图的状态时如何保留子视图的状态?

如何从结构视图数组中提取状态? SwiftUI

如何知道 UIKit 视图控制器中的 swiftUI 事件? ||如何提供 swiftUI 和 uikit 之间的通信