ios 按钮未运行操作

rryofs0p  于 2023-01-14  发布在  iOS
关注(0)|答案(1)|浏览(111)

我正在为我的应用构建一个登录,它调用服务器上的API并返回用户信息和一个 *JWT令牌 *。我决定将视图拆分为单独的代码块,以便稍后将它们移动到项目中它们自己的文件中。然而,由于我已经这样做了,所以登录表单中的按钮不会运行ViewModel中的登录函数,甚至也不会打印和输出到控制台。
我在这里包含了我的ContentView.swift来展示我的想法和基本设置。

struct ContentView: View {
    
    @StateObject private var loginVM = LoginViewModel()
    @StateObject private var projectListVM = ProjectListViewModel()
    @State private var isSecured: Bool = true
    
    var body: some View {
        Group {
            if loginVM.isAuthenticated {
                MainView()
            } else {
                LoginView()
            }
        }
    }
}

struct LoginView: View {
    @StateObject private var loginVM = LoginViewModel()
    @StateObject private var projectListVM = ProjectListViewModel()
    @State private var isPasswordVisible = false
    var body: some View {
        Form {
            VStack(alignment: .center, spacing: 0.0) {
                Spacer()
                VStack(alignment: .leading, spacing: 10)  {
                    Text("Email")
                        .font(.fieldLabel)
                        .foregroundColor(Color.secondary01Light)
                        .frame(alignment: .leading)
                    TextField("Username", text: $loginVM.username)
                        .keyboardType(.emailAddress)
                        .textInputAutocapitalization(.never)
                        .padding()
                        .overlay {
                            RoundedRectangle(cornerRadius: 4, style: .continuous)
                                .stroke(Color(UIColor.systemGray4), lineWidth: 1)
                        }
                }
                
                VStack(alignment: .leading, spacing: 10) {
                    Spacer()
                    Text("Password")
                        .font(.fieldLabel)
                        .foregroundColor(Color.secondary01Light)
                        .frame(alignment: .leading)
                    SecureField("Password", text: $loginVM.password)
                        .padding()
                        .overlay {
                            RoundedRectangle(cornerRadius: 4, style: .continuous)
                                .stroke(Color(UIColor.systemGray4), lineWidth: 1)
                        }
                }
            }
            
            VStack {
                Button(action: {
                    print("Login Tapped")
                    loginVM.login()
                }) {
                    Text("Sign In")
                        .frame(maxWidth: .infinity)
                        .padding(8)
                        .cornerRadius(8)
                }
                .padding(.top, 30)
                .frame(height: nil)
                .buttonStyle(.borderedProminent)
                .tint(Color.primary01)
                .controlSize(.regular)
                .font(.custom("Poppins-ExtraBold", size: 16))
                .foregroundColor(.white)
            }           
        }
    }
}

上面的代码显示了表单中的按钮,它带有一个操作,在该操作中调用了login()方法和print语句。
当我点击模拟器中的按钮时,我甚至没有在控制台中得到输出,它似乎也没有运行我的登录功能。
下面是我的LoginViewModel,我在过去的工作中没有遇到任何问题。

class LoginViewModel: ObservableObject {
    
    var username: String = ""
    var password: String = ""
    @Published var isAuthenticated: Bool = false
    
    func login() {
        print("Login Called")
        Webservice().login(username: username, password: password) { result in
            print("Login API Call Made")
            switch result {
                case .success(_):
                    print("Got User Data")
                    DispatchQueue.main.async {
                        self.isAuthenticated = true
                    }
                case .failure(let error):
                    print(error.localizedDescription)
            }
        }
        
    }
}

表单字段已就位,@StateObject已在视图中,但似乎不想触发。

eyh26e7m

eyh26e7m1#

loginVM初始化了两次!一次在ContentView中,另一次在LoginView中(都使用@StateObject)......因此,您创建了两个不相连的不同状态。
你要做的是在ContentView中只创建一次,然后将它传递给LoginView(例如,使用.environmentObject):

struct ContentView: View {
    
    // here you create/initialize the object
    @StateObject private var loginVM = LoginViewModel()
    
    var body: some View {
        Group {
            if loginVM.isAuthenticated {
                MainView()
            } else {
                LoginView()
            }
        }
        .environmentObject(loginVM) // pass the object to all child views
    }
}

struct LoginView: View {

    // here you get the passed Object from the environment
    @EnvironmentObject private var loginVM: LoginViewModel

    var body: some View {
        // ...
    }
}

相关问题