在SKScene中展示UIAlert的方法及无显示问题求助(附代码)
在SKScene中展示UIAlert的问题排查与解决
嘿,我来帮你搞定这个SKScene里弹不出UIAlert的问题!你当前的代码没反应,大概率是获取视图控制器的路径出了问题——链式调用self.view?.window?.rootViewController里的某一步可能返回了nil,或者拿到的控制器并不是当前能弹出弹窗的活跃控制器。
问题分析
你写的这段代码:
var alertController = UIAlertController(title: "Nothing Selected", message: "You have selected a picture.", preferredStyle: UIAlertControllerStyle.alert) alertController.addAction(UIAlertAction(title: "HI!", style: UIAlertActionStyle.cancel, handler: nil)) self.view?.window?.rootViewController?.present(alertController, animated: true, completion: nil)
这里的self.view?.window?.rootViewController存在几个潜在问题:
- 如果
self.view还没被添加到窗口上,self.view?.window会是nil - 如果你的App结构是导航控制器(UINavigationController)或标签栏控制器(UITabBarController),直接用
rootViewController拿到的是根控制器,而不是当前显示的子控制器,这时候调用present可能不会生效
解决方案
我给你几个靠谱的实现方式,按推荐程度排序:
1. 获取顶层视图控制器(最通用,推荐)
写一个UIViewController的扩展,用来找到当前App中最顶层的活跃视图控制器,不管你的界面结构是啥都能用:
extension UIViewController { static func topMostViewController() -> UIViewController? { // 找到当前的keyWindow guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return nil } var topVC = keyWindow.rootViewController // 一直找到最上层的presented控制器 while let presentedVC = topVC?.presentedViewController { topVC = presentedVC } return topVC } }
然后在你的SKScene里这么调用:
// 先拿到顶层控制器,再弹alert if let topViewController = UIViewController.topMostViewController() { let alertController = UIAlertController(title: "Nothing Selected", message: "You have selected a picture.", preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "HI!", style: .cancel, handler: nil)) topViewController.present(alertController, animated: true, completion: nil) }
2. 直接获取SKView的父视图控制器
如果你的SKScene是直接添加在某个UIViewController的SKView上的,可以直接拿SKView的parentViewController:
if let parentVC = self.view?.parentViewController { let alertController = UIAlertController(title: "Nothing Selected", message: "You have selected a picture.", preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "HI!", style: .cancel, handler: nil)) parentVC.present(alertController, animated: true, completion: nil) }
这个方法更简洁,但只适用于SKScene的视图直接隶属于某个ViewController的情况。
3. 排查原代码的nil问题
如果想继续用你原来的思路,可以先打印排查哪一步是nil:
print("self.view: \(self.view)") print("self.view?.window: \(self.view?.window)") print("rootViewController: \(self.view?.window?.rootViewController)")
如果其中某一行输出是nil,就说明问题出在这一步——比如self.view为nil,说明你的SKScene还没被正确添加到视图层级里。
额外提示
记得在主线程里调用present方法!虽然UIKit的方法默认应该在主线程,但如果你的代码是在后台线程执行的,也会导致alert不显示。可以加个判断确保在主线程:
DispatchQueue.main.async { // 这里写弹alert的代码 }
内容的提问来源于stack exchange,提问作者B.Mahadewa
相关产品推荐
相关产品推荐

