iOS13+Swift5下弹出UIAlertController时ViewController重载问题求助
我帮你分析下这个问题的核心:你遇到的情况大概率是按钮的默认行为或者额外绑定的逻辑触发了ViewController的重新加载,再加上你用了DispatchQueue.main.async延迟了alert的显示,才会出现先看到页面重载、再弹出弹窗的顺序问题。下面是具体的解决方案:
1. 修正按钮类型,避免默认行为干扰
如果你的注册按钮是通过Storyboard/Xib创建的,先检查它的类型:System类型的按钮自带默认的交互反馈,甚至在某些场景下会意外触发父视图的刷新逻辑。把它改成Custom类型试试:
- 选中按钮,在右侧Attributes Inspector里找到「Type」选项,切换为「Custom」。
如果是代码创建的按钮,初始化时直接指定custom类型:
let registerButton = UIButton(type: .custom)
2. 梳理按钮点击逻辑,分离弹窗与重载操作
检查你的按钮点击方法,是不是在弹出alert的同时,还执行了会导致页面刷新/控制器重载的代码?比如不小心绑定了表单提交、导航栈跳转,或者调用了reloadInputViews()这类刷新方法。
正确的做法是:先弹出alert,把需要执行的重载逻辑放到alert的按钮回调里(如果确实需要的话),示例代码如下:
@IBAction func registerButtonTapped(_ sender: UIButton) { let alert = UIAlertController(title: "Your title", message: "Your message", preferredStyle: .alert) // OK按钮点击后再执行重载逻辑 let okAction = UIAlertAction(title: "OK", style: .default) { [weak self] _ in self?.performViewControllerReload() } alert.addAction(okAction) // 取消按钮用.cancel风格更符合系统交互规范 let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) alert.addAction(cancelAction) // 按钮点击回调本身就在主线程,不需要额外包DispatchQueue.main.async self.present(alert, animated: true) } // 封装你的重载逻辑 private func performViewControllerReload() { // 这里写你需要的页面刷新/控制器重载代码 // 比如重新加载数据、刷新UI组件等 }
3. 移除不必要的DispatchQueue.main.async
UIKit的按钮点击回调本身就是在主线程执行的,你不需要把present方法包在DispatchQueue.main.async里——这反而会让alert的显示被延迟,导致重载逻辑先执行。直接调用self.present(alert, animated: true)就可以了。
4. 排查生命周期方法中的意外刷新
另外,检查一下你的ViewController的viewWillAppear/viewDidAppear方法,是不是写了每次页面出现都会执行的刷新逻辑?如果按钮点击时意外触发了这些生命周期方法(比如误触了导航栈操作),也会导致页面先重载。确保这些方法里的刷新逻辑只有在真正需要的时候才执行。
内容的提问来源于stack exchange,提问作者Hasnain ahmad

