枚举类型的 SwiftUi @State 变量为 nil
SwiftUi @State variable of type enum is nil
我有四个观点:
LoginView()
SignInWithEmailView()
SignUpView()
ForgotPasswordView()
LoginView:
struct LoginView: View {
enum Action {
case signUp, resetPW
}
@State private var showSheet = false
@State private var action: Action?
init() {
print(self.action) //prints nil
}
var body: some View {
VStack {
SignInWithEmailView(showSheet: $showSheet, action: $action)
SignInWithAppleView()
.frame(width: 200, height: 50)
Spacer()
}
.sheet(isPresented: $showSheet) {
if self.action == .signUp {
SignUpView()
} else {
ForgotPasswordView()
}
}
}
}
SignInWithEmailView :
struct SignInWithEmailView: View {
@EnvironmentObject var userInfo: UserInfo
@State var user: UserViewModel = UserViewModel()
@Binding var showSheet: Bool
@Binding var action: LoginView.Action?
@State private var showAlert = false
@State private var authError: EmailAuthError?
var body: some View {
VStack {
CustomTextField(secureInput: false, titleKey: "Email Address",
fieldText: self.$user.email)
.autocapitalization(.none)
.keyboardType(.emailAddress)
CustomTextField(secureInput: true, titleKey: "Password", fieldText: $user.password)
HStack {
Spacer()
Button(action: {
self.showSheet = true
self.action = .resetPW
}) {
Text("Forgot Password")
}
}.padding(.bottom)
VStack(spacing: 10) {
FormButton(buttonText: "Login", buttonAction: {
FBAuth.authenticate(withEmail: self.user.email,
password: self.user.password) { (result) in
switch result {
case .failure(let error):
self.authError = error
self.showAlert = true
case .success( _):
print("Signed in")
}
}
})
.opacity(user.isLogInComplete ? 1 : 0.5)
.disabled(!user.isLogInComplete)
FormButton(buttonText: "Sign UP", buttonAction: {
self.showSheet = true
self.action = .signUp
})
}
.alert(isPresented: $showAlert) {
Alert(title: Text("Login Error"), message: Text(self.authError?.localizedDescription ?? "Unknown error"), dismissButton: .default(Text("OK")) {
if self.authError == .incorrectPassword {
self.user.password = ""
}else {
self.user.email = ""
self.user.password = ""
}
})
}
}
.padding(.top, 100)
.frame(width: 300)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
SignUpView :
struct SignUpView: View {
@EnvironmentObject var userInfo: UserInfo
@State var user: UserViewModel = UserViewModel()
@Environment(\.presentationMode) var presentationMode
@State private var showError = false
@State private var errorString = ""
var body: some View {
NavigationView {
VStack {
Group {
AvatarSelection()
VStack(alignment: .leading) {
CustomTextField(secureInput: false, titleKey: "Full Name", fieldText: self.$user.fullname)
if !user.validNameText.isEmpty {
Text(user.validNameText).font(.caption).foregroundColor(.red)
}
}
VStack(alignment: .leading) {
CustomTextField(secureInput: false, titleKey: "Email Address", fieldText: self.$user.email).autocapitalization(.none).keyboardType(.emailAddress)
if !user.validEmailAddressText.isEmpty {
Text(user.validEmailAddressText).font(.caption).foregroundColor(.red)
}
}
VStack(alignment: .leading) {
CustomTextField(secureInput: true, titleKey: "Password", fieldText: self.$user.password)
if !user.validPasswordText.isEmpty {
Text(user.validPasswordText).font(.caption).foregroundColor(.red)
}
}
VStack(alignment: .leading) {
CustomTextField(secureInput: true, titleKey: "Confirm Password", fieldText: self.$user.confirmPassword)
if !user.passwordsMatch(_confirmPW: user.confirmPassword) {
Text(user.validConfirmPasswordText).font(.caption).foregroundColor(.red)
}
}
}.frame(width: 300)
.textFieldStyle(RoundedBorderTextFieldStyle())
VStack(spacing: 20 ) {
FormButton(buttonText: "Sign Up", buttonAction: {
// Signup
FBAuth.createUser(withEmail: self.user.email,
name: self.user.fullname,
password: self.user.password) { (result) in
switch result {
case .failure(let error):
self.errorString = error.localizedDescription
self.showError = true
case .success( _):
print("Account Creation Successful")
}
}
})
.opacity(user.isSignInComplete ? 1 : 0.5)
.disabled(!user.isSignInComplete)
Spacer()
}.padding()
}.padding(.top)
.alert(isPresented: $showError) {
Alert(title: Text("Error Creating an Account"), message: Text(self.errorString), dismissButton: .default(Text("OK")))
}
.navigationBarTitle("Sign Up", displayMode: .inline)
.navigationBarItems(trailing: Button("Dismiss") {
self.presentationMode.wrappedValue.dismiss()
})
}
}
}
ForgotPasswordView:
struct ForgotPasswordView: View {
@State var user: UserViewModel = UserViewModel()
@Environment(\.presentationMode) var presentationMode
@State private var showAlert = false
@State private var errString: String?
var body: some View {
NavigationView {
VStack {
TextField("Enter email address", text: $user.email).autocapitalization(.none).keyboardType(.emailAddress)
FormButton(buttonText: "Submit", buttonAction: {
FBAuth.resetPassword(email: self.user.email) { (result) in
switch result {
case .failure(let error):
self.errString = error.localizedDescription
case .success( _):
break
}
self.showAlert = true
}
})
.disabled(!user.isEmailValid(_email: user.email))
Spacer()
}.padding(.top)
.frame(width: 300)
.textFieldStyle(RoundedBorderTextFieldStyle())
.navigationBarTitle("Request a password reset", displayMode: .inline)
.navigationBarItems(trailing: Button("Dismiss") {
self.presentationMode.wrappedValue.dismiss()
})
.alert(isPresented: $showAlert) {
Alert(title: Text("Password Reset"), message: Text(self.errString ?? "Success, Password reset email was sent, Check your email"), dismissButton: .default(Text("OK")) {
self.presentationMode.wrappedValue.dismiss()
})
}
}
}
}
问题:
在登录视图中,我第一次点击注册按钮时,sheet 打开了 ForgotPasswordView() // 这是错误的
当我关闭 sheet 并点击忘记密码时,sheet 打开忘记密码 // 这是正确的
当我关闭 sheet 并再次点击注册按钮时,sheet 打开 SignUpView // 这是正确的
如何在第一次尝试时打开 SignupView?
我解开了这个谜,在 LoginView :
我改变了这个:
SignInWithEmailView(showSheet: $showSheet, action: $action)
对此:
SignInWithEmailView(showSheet: $showSheet, action: self.action == nil ? $action : $action)
它就像一个魅力 ;)
我有四个观点:
LoginView()
SignInWithEmailView()
SignUpView()
ForgotPasswordView()
LoginView:
struct LoginView: View {
enum Action {
case signUp, resetPW
}
@State private var showSheet = false
@State private var action: Action?
init() {
print(self.action) //prints nil
}
var body: some View {
VStack {
SignInWithEmailView(showSheet: $showSheet, action: $action)
SignInWithAppleView()
.frame(width: 200, height: 50)
Spacer()
}
.sheet(isPresented: $showSheet) {
if self.action == .signUp {
SignUpView()
} else {
ForgotPasswordView()
}
}
}
}
SignInWithEmailView :
struct SignInWithEmailView: View {
@EnvironmentObject var userInfo: UserInfo
@State var user: UserViewModel = UserViewModel()
@Binding var showSheet: Bool
@Binding var action: LoginView.Action?
@State private var showAlert = false
@State private var authError: EmailAuthError?
var body: some View {
VStack {
CustomTextField(secureInput: false, titleKey: "Email Address",
fieldText: self.$user.email)
.autocapitalization(.none)
.keyboardType(.emailAddress)
CustomTextField(secureInput: true, titleKey: "Password", fieldText: $user.password)
HStack {
Spacer()
Button(action: {
self.showSheet = true
self.action = .resetPW
}) {
Text("Forgot Password")
}
}.padding(.bottom)
VStack(spacing: 10) {
FormButton(buttonText: "Login", buttonAction: {
FBAuth.authenticate(withEmail: self.user.email,
password: self.user.password) { (result) in
switch result {
case .failure(let error):
self.authError = error
self.showAlert = true
case .success( _):
print("Signed in")
}
}
})
.opacity(user.isLogInComplete ? 1 : 0.5)
.disabled(!user.isLogInComplete)
FormButton(buttonText: "Sign UP", buttonAction: {
self.showSheet = true
self.action = .signUp
})
}
.alert(isPresented: $showAlert) {
Alert(title: Text("Login Error"), message: Text(self.authError?.localizedDescription ?? "Unknown error"), dismissButton: .default(Text("OK")) {
if self.authError == .incorrectPassword {
self.user.password = ""
}else {
self.user.email = ""
self.user.password = ""
}
})
}
}
.padding(.top, 100)
.frame(width: 300)
.textFieldStyle(RoundedBorderTextFieldStyle())
}
}
SignUpView :
struct SignUpView: View {
@EnvironmentObject var userInfo: UserInfo
@State var user: UserViewModel = UserViewModel()
@Environment(\.presentationMode) var presentationMode
@State private var showError = false
@State private var errorString = ""
var body: some View {
NavigationView {
VStack {
Group {
AvatarSelection()
VStack(alignment: .leading) {
CustomTextField(secureInput: false, titleKey: "Full Name", fieldText: self.$user.fullname)
if !user.validNameText.isEmpty {
Text(user.validNameText).font(.caption).foregroundColor(.red)
}
}
VStack(alignment: .leading) {
CustomTextField(secureInput: false, titleKey: "Email Address", fieldText: self.$user.email).autocapitalization(.none).keyboardType(.emailAddress)
if !user.validEmailAddressText.isEmpty {
Text(user.validEmailAddressText).font(.caption).foregroundColor(.red)
}
}
VStack(alignment: .leading) {
CustomTextField(secureInput: true, titleKey: "Password", fieldText: self.$user.password)
if !user.validPasswordText.isEmpty {
Text(user.validPasswordText).font(.caption).foregroundColor(.red)
}
}
VStack(alignment: .leading) {
CustomTextField(secureInput: true, titleKey: "Confirm Password", fieldText: self.$user.confirmPassword)
if !user.passwordsMatch(_confirmPW: user.confirmPassword) {
Text(user.validConfirmPasswordText).font(.caption).foregroundColor(.red)
}
}
}.frame(width: 300)
.textFieldStyle(RoundedBorderTextFieldStyle())
VStack(spacing: 20 ) {
FormButton(buttonText: "Sign Up", buttonAction: {
// Signup
FBAuth.createUser(withEmail: self.user.email,
name: self.user.fullname,
password: self.user.password) { (result) in
switch result {
case .failure(let error):
self.errorString = error.localizedDescription
self.showError = true
case .success( _):
print("Account Creation Successful")
}
}
})
.opacity(user.isSignInComplete ? 1 : 0.5)
.disabled(!user.isSignInComplete)
Spacer()
}.padding()
}.padding(.top)
.alert(isPresented: $showError) {
Alert(title: Text("Error Creating an Account"), message: Text(self.errorString), dismissButton: .default(Text("OK")))
}
.navigationBarTitle("Sign Up", displayMode: .inline)
.navigationBarItems(trailing: Button("Dismiss") {
self.presentationMode.wrappedValue.dismiss()
})
}
}
}
ForgotPasswordView:
struct ForgotPasswordView: View {
@State var user: UserViewModel = UserViewModel()
@Environment(\.presentationMode) var presentationMode
@State private var showAlert = false
@State private var errString: String?
var body: some View {
NavigationView {
VStack {
TextField("Enter email address", text: $user.email).autocapitalization(.none).keyboardType(.emailAddress)
FormButton(buttonText: "Submit", buttonAction: {
FBAuth.resetPassword(email: self.user.email) { (result) in
switch result {
case .failure(let error):
self.errString = error.localizedDescription
case .success( _):
break
}
self.showAlert = true
}
})
.disabled(!user.isEmailValid(_email: user.email))
Spacer()
}.padding(.top)
.frame(width: 300)
.textFieldStyle(RoundedBorderTextFieldStyle())
.navigationBarTitle("Request a password reset", displayMode: .inline)
.navigationBarItems(trailing: Button("Dismiss") {
self.presentationMode.wrappedValue.dismiss()
})
.alert(isPresented: $showAlert) {
Alert(title: Text("Password Reset"), message: Text(self.errString ?? "Success, Password reset email was sent, Check your email"), dismissButton: .default(Text("OK")) {
self.presentationMode.wrappedValue.dismiss()
})
}
}
}
}
问题:
在登录视图中,我第一次点击注册按钮时,sheet 打开了 ForgotPasswordView() // 这是错误的
当我关闭 sheet 并点击忘记密码时,sheet 打开忘记密码 // 这是正确的
当我关闭 sheet 并再次点击注册按钮时,sheet 打开 SignUpView // 这是正确的
如何在第一次尝试时打开 SignupView?
我解开了这个谜,在 LoginView :
我改变了这个:
SignInWithEmailView(showSheet: $showSheet, action: $action)
对此:
SignInWithEmailView(showSheet: $showSheet, action: self.action == nil ? $action : $action)
它就像一个魅力 ;)