Swift登录流程中Xib视图无法正常dismiss的问题求助
场景描述
我为登录场景创建了两个Xib文件,点击按钮先展示第一个Xib(SigningAlert),在该Xib内点击按钮会在其上方展示第二个Xib(LoginVC)。在第二个Xib中调用登录API,成功后尝试通过self.dismiss(animated: true, completion: nil)关闭第二个Xib,但视图并未消失。断点已触发,说明代码执行到了该语句,但无效果。
相关代码
展示第一个Xib的代码:
let signingAlert = SigningAlert() signingAlert.modalPresentationStyle = .custom present(signingAlert,animated: true,completion: nil)
调用第二个Xib的代码:
@IBAction func loginBtnTapped(_ sender: Any) { let loginAlert = LoginVC() loginAlert.modalPresentationStyle = .popover present(loginAlert,animated: true,completion: nil) // self.revealViewController().revealToggle(animated: true) }
API成功时的处理代码:
self.dismiss(animated: true, completion: nil)
完整的登录API调用代码:
func loginAPICall(){ activityIndicator.startAnimating() activityIndicator.isHidden = false shadowView.isHidden = false let param1 = "username="+userNameTxt.text! let param2 = param1+"&password="+passwordTxt.text! let param = param2+"&grant_type=password" print(param) LoginService.instance.LogInUSer(body: param) { (success) in if success{ let status = LoginService.instance.status if status == 500{ print("500") self.showAlert(message: "Error!.Server not found") self.activityIndicator.stopAnimating() self.activityIndicator.isHidden = true self.shadowView.isHidden = true } else if status == 404{ print("404") self.showAlert(message: "Error!. Data not found try again") self.activityIndicator.stopAnimating() self.activityIndicator.isHidden = true self.shadowView.isHidden = true } else if status == 400{ self.showAlert(message: "Error!. Username or password is incorrect.") self.activityIndicator.stopAnimating() self.activityIndicator.isHidden = true self.shadowView.isHidden = true } else if status == 401{ print("401") self.activityIndicator.stopAnimating() self.activityIndicator.isHidden = true self.shadowView.isHidden = true } else if status == 200{ self.showsuccessAlert(message: "You are successfully LoggedIn") self.dismiss(animated: true, completion: nil) self.activityIndicator.stopAnimating() self.activityIndicator.isHidden = true self.shadowView.isHidden = true let userName = LoginService.instance.loginModelInstance[0].userName let accessToken = LoginService.instance.loginModelInstance[0].accessToken let userId = LoginService.instance.loginModelInstance[0].userID UserDefaults.standard.setValue("true", forKey: "status") UserDefaults.standard.set(userName, forKey:"name") UserDefaults.standard.set(userId, forKey:"userId") UserDefaults.standard.set(accessToken, forKey:"accessToken") UserDefaults.standard.synchronize() } else{ self.showAlert(message: "Error!. Try again") self.activityIndicator.stopAnimating() self.activityIndicator.isHidden = true self.shadowView.isHidden = true } }else{ let status = LoginService.instance.status print(status) self.showAlert(message: "Error!. Try again") self.activityIndicator.stopAnimating() self.activityIndicator.isHidden = true self.shadowView.isHidden = true } } }
我来帮你一步步排查这个问题,大概率是以下几个原因导致的,逐个尝试修复:
1. 调整模态展示样式
你给LoginVC设置的是.popover模态样式,这种样式在iOS(尤其是iPhone)上的表现和常规弹窗不太一样,它的dismiss逻辑有特殊处理,很可能是导致失效的核心原因。建议把它改成更适合弹窗的样式,比如和第一个Xib一致的.custom,或者用.overFullScreen:
@IBAction func loginBtnTapped(_ sender: Any) { let loginAlert = LoginVC() // 替换成合适的模态样式 loginAlert.modalPresentationStyle = .overFullScreen present(loginAlert,animated: true,completion: nil) }
2. 确保在主线程执行dismiss
API的回调方法通常是在后台线程执行的,而所有UI操作必须在主线程中进行。虽然你看到断点触发了,但如果不在主线程调用dismiss,系统可能不会处理这个UI请求。把dismiss代码包在主线程异步调用里:
else if status == 200{ self.showsuccessAlert(message: "You are successfully LoggedIn") // 切换到主线程执行UI操作 DispatchQueue.main.async { self.dismiss(animated: true, completion: nil) } // 其他逻辑保持不变... }
3. 检查presenter的层级关系
有时候直接调用self.dismiss可能因为模态层级的问题没生效,可以尝试让当前视图的presentingViewController来执行dismiss操作,确保是正确的层级关闭:
DispatchQueue.main.async { // 让presentingViewController来处理dismiss self.presentingViewController?.dismiss(animated: true, completion: nil) }
如果需要一次性关闭所有模态视图回到根控制器,也可以用这个:
DispatchQueue.main.async { self.view.window?.rootViewController?.dismiss(animated: true, completion: nil) }
4. 避免弹窗干扰dismiss
你在dismiss之前调用了showsuccessAlert,如果这个方法里弹出了另一个UIAlertController,会抢占当前的模态层级,导致后续的dismiss被干扰。建议把dismiss放到成功弹窗的关闭回调里(如果你的showsuccessAlert支持completion的话):
// 假设你的showsuccessAlert添加了completion参数 self.showsuccessAlert(message: "You are successfully LoggedIn") { DispatchQueue.main.async { self.dismiss(animated: true, completion: nil) } }
先从调整模态样式和主线程调用这两个最常见的问题入手,基本就能解决dismiss无效的问题了。
内容的提问来源于stack exchange,提问作者Awais

