You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift登录流程中Xib视图无法正常dismiss的问题求助

问题: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:00:33