我正在为我的应用构建一个登录,它调用服务器上的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
已在视图中,但似乎不想触发。
1条答案
按热度按时间eyh26e7m1#
loginVM
初始化了两次!一次在ContentView
中,另一次在LoginView
中(都使用@StateObject
)......因此,您创建了两个不相连的不同状态。你要做的是在
ContentView
中只创建一次,然后将它传递给LoginView
(例如,使用.environmentObject
):