Swift UIPageViewController触发Window should be nonnil断言且内容不显示
问题复现
当PageController尝试展示其内容时,控制台输出如下断言提示:
"[Assert] Window should be nonnil here unless a subclass is mistakenly sending this to a child when no window can be found"
应用未崩溃,但PageController对应内容无法正常显示,业务代码实现如下:
class RulesPageViewController: UIPageViewController { var rulesDelegate: RulesPageVeiwControllerDelegate? var pageHeadings = ["1st page","2nd","3rd"] var currentIndex = 0 override func viewDidLoad() { super.viewDidLoad() self.dataSource = self self.delegate = self if let startingViewController = contentViewController(at: 0) { self.setViewControllers([startingViewController], direction: .forward, animated: false, completion: nil) } } func contentViewController(at index: Int)-> PageContentViewController? { if(index < 0 || index >= pageHeadings.count) { return nil } if let pageContentViewController = UIStoryboard(name: "GameRules", bundle: nil).instantiateViewController(withIdentifier: "PageContentViewController") as? PageContentViewController{ pageContentViewController.index = index return pageContentViewController } return nil } } extension RulesPageViewController: UIPageViewControllerDelegate { func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { if completed { if let contentViewController = pageViewController.viewControllers?.first as? PageContentViewController { currentIndex = contentViewController.index rulesDelegate?.didUpdatePageIndex(currentIndex: currentIndex) } } } } extension RulesPageViewController: UIPageViewControllerDataSource { func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { var index = (viewController as! PageContentViewController).index index -= 1 return contentViewController(at: index) } func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { var index = (viewController as! PageContentViewController).index index += 1 return contentViewController(at: index) } }
原因说明
该断言触发的核心原因是viewDidLoad执行时,UIPageViewController的视图尚未挂载到App的window层级上,此时调用setViewControllers会触发系统内部的非空校验失败。
解决方案
- 调整初始控制器设置的执行时机:将
viewDidLoad中的初始控制器设置逻辑迁移到viewDidAppear(_:)中,添加标识避免重复执行:
// 新增属性标记初始控制器是否已设置 private var isInitialPageSet = false override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) guard !isInitialPageSet else { return } if let startingViewController = contentViewController(at: 0) { self.setViewControllers([startingViewController], direction: .forward, animated: false, completion: nil) } isInitialPageSet = true }
- 如果需要更早执行设置,可替换为
viewWillAppear(_:)方法,绝大多数场景下此时视图已关联到window,不会触发断言。 - 额外校验:如果是代码初始化的
RulesPageViewController,确认使用的是指定初始化方法init(transitionStyle:navigationOrientation:options:),而非默认的init(nibName:bundle:),初始化参数配置错误也会触发该问题。
内容的提问来源于stack exchange,提问作者Dmitrii Sokolov
相关产品推荐
相关产品推荐

