SwiftUI集成Firebase注册时第二个Alert弹窗一闪而过如何解决
问题根源
- 第一是逻辑错误:你把
self.showVerifyEmail = true写在了result判断的分支外面,不管接口返回成功还是失败,这段代码都会执行。如果是注册失败的场景,会先后触发showError = true和showVerifyEmail = true两个状态变更 - 第二是SwiftUI的限制:同一视图层级下挂载多个
alert(isPresented:)修饰符时,同一时间只能有一个alert生效,同时触发两个alert的显示状态会导致系统渲染冲突,就会出现alert一闪而过的问题
解决方案
你提到的用枚举管理Alert状态是目前最规范的解决方式,配合SwiftUI的alert(item:)修饰符可以完全避免多alert冲突问题,同时还要修复原有逻辑的错误:
- 定义Alert枚举统一管理所有弹窗类型
- 移除原有的三个独立状态变量,替换为单个枚举类型的可选状态
- 调整回调逻辑,仅在注册成功时触发验证邮件提示
- 统一使用单个
alert(item:)修饰符处理所有弹窗
修改后的核心代码示例
// 首先定义Alert类型枚举 enum AlertType: Identifiable { case error(String) case verifyEmail // 遵循Identifiable协议要求的id属性 var id: Int { switch self { case .error: return 0 case .verifyEmail: return 1 } } } struct SignUpView: View { @EnvironmentObject var userInfo: UserInfo @State var user: UserViewModel = UserViewModel() @Environment(\.presentationMode) var presentationMode // 替换原有三个状态变量,统一用枚举管理 @State private var alertType: AlertType? var body: some View { NavigationView { VStack { Group { VStack(alignment: .leading) { TextField("Full Name", text: self.$user.fullname).autocapitalization(.words) if !user.validNameText.isEmpty { Text(user.validNameText).font(.caption).foregroundColor(.red) } } VStack(alignment: .leading) { TextField("Email Address", text: self.$user.email).autocapitalization(.none).keyboardType(.emailAddress) if !user.validEmailAddressText.isEmpty { Text(user.validEmailAddressText).font(.caption).foregroundColor(.red) } } VStack(alignment: .leading) { SecureField("Password", text: self.$user.password) if !user.validPasswordText.isEmpty { Text(user.validPasswordText).font(.caption).foregroundColor(.red) } } VStack(alignment: .leading) { SecureField("Confirm Password", text: self.$user.confirmPassword) if !user.passwordsMatch(_confirmPW: user.confirmPassword) { Text(user.validConfirmPasswordText).font(.caption).foregroundColor(.red) } } }.frame(width: 300) .textFieldStyle(RoundedBorderTextFieldStyle()) VStack(spacing: 20 ) { Button(action: { FBAuth.createUser(withEmail: self.user.email, name: self.user.fullname, password: self.user.password) { (result) in // 所有UI状态修改放到主线程执行,避免Firebase回调在后台线程导致的渲染问题 DispatchQueue.main.async { switch result { case .failure(let error): // 失败时设置错误弹窗 self.alertType = .error(error.localizedDescription) case .success( _): print("Account creation successful") // 仅成功时设置验证邮件弹窗 self.alertType = .verifyEmail } } } }) { Text("Register") .frame(width: 200) .padding(.vertical, 15) .background(Color(.systemBlue)) .cornerRadius(8) .foregroundColor(.white) .opacity(user.isSignInComplete ? 1 : 0.75) } .disabled(!user.isSignInComplete) Spacer() }.padding() }.padding(.top) // 移除原来的两个alert修饰符,替换为单个item绑定的alert .alert(item: $alertType) { type in switch type { case .error(let msg): return Alert(title: Text("创建账号出错"), message: Text(msg), dismissButton: .default(Text("确定"))) case .verifyEmail: return Alert(title: Text("邮件已发送"), message: Text("验证邮件已发送,请检查你的收件箱,若未找到可查看垃圾邮件文件夹"), dismissButton: .default(Text("确定"))) } } .navigationBarTitle("注册", displayMode: .inline) .navigationBarItems(trailing: Button("关闭") { self.presentationMode.wrappedValue.dismiss() }) } } }
内容的提问来源于stack exchange,提问作者LMA
相关产品推荐
相关产品推荐

