添加页面时 UIPageViewController 崩溃

Posted

技术标签:

【中文标题】添加页面时 UIPageViewController 崩溃【英文标题】:Crash in UIPageViewController when adding pages 【发布时间】:2017-11-27 15:09:47 【问题描述】:

在我正在开发的 ios 11 应用程序中(使用 Swift 4),我需要将页面动态添加到 UIPageViewController。但是,在某些情况下,我会收到以下崩溃错误 (NSInternalInconsistencyException):

2017-11-27 14:55:54.787260+0000 MyApp[380:79434] *** Assertion failure in -[UIPageViewController _flushViewController:animated:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3698.21.8/UIPageViewController.m:2124
2017-11-27 14:55:54.791022+0000 MyApp[380:79434] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Don't know about flushed view <UIView: 0x12dd48ac0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x1c003c280>>'

我对 iOS 开发非常陌生,所以如果答案很明显,我很抱歉,但我很难找到崩溃的根本原因。记录的消息也不是很有帮助...

这是我用来添加页面的代码:

//Inflate the view controller
let viewController = newViewController(param: someParam )

//Add it to the view controllers pool
viewControllersOrdered.insert(viewController, at: getInsertionIndex(param: someOtherParam) )

//Add it to the pageViewController
pageViewController.setViewControllers([viewController], direction: .forward, animated: false, completion: nil)

//Force cache to be cleared
pageViewController.dataSource = nil;
pageViewController.dataSource = self;

getInsertionIndex 函数工作正常,这不是崩溃的根源。

【问题讨论】:

你在做什么很奇怪。手头有一个带有 UIPageViewController 的视图控制器池是不正常的。整个想法是它只有 一个 视图控制器。否则,你就是在浪费内存。您必须“清除缓存”的事实表明这是不正常的,并且不会起作用;你不能干涉 UIPageVC 的缓存机制。您应该只实现委托方法并让 UIPageViewController 进行缓存并管理子视图控制器。 @matt 您好,感谢您的回复。我正在清除缓存,因为当我删除视图时,viewController 仍然会让用户滚动到它们,因为 getBefore/After 方法已经被调用。 pageViewController 界面似乎确实在与页面的动态添加/删除作斗争。我错过了什么吗? 你什么都没有错过!你是绝对正确的。问题是您选择了一个视图控制器架构,然后您必须与之抗争。那是难闻的气味。请参阅下面的答案。 也许这篇文章中的答案:assertion-failure-in-uipageviewcontroller) 可以帮到你。如果没有,请提供更多代码...而且“清除缓存”也不正常。 【参考方案1】:

在我正在开发的 iOS 11 应用程序中(使用 Swift 4),我需要将页面动态添加到 UIPageViewController。

听起来您的意思是:在用户真正尝试“翻页”之前,您不知道下一个/上一个视图控制器将是什么。在这种情况下,滚动 UIPageViewController 不适合您的架构(因为,正如您已经发现的那样,它会预先缓存下一页和上一页)。你有两个选择:

使用页面卷曲 UIPageViewController。它不会预先缓存其页面,因此在用户真正要求翻页之前不会要求您做出决定。

根本不要使用 UIPageViewController;使用分页水平滚动视图并自己管理内容视图。

此外,如果您使用的是 UIPageViewController,则在任何情况下,您都不应该持有保留的子视图控制器列表。这就是 UIPageViewController 的工作。您的工作只是提供下一个或上一个视图控制器,您应该根据需要而不是其他时间创建它,并将其释放到 UIPageViewController 的唯一控件中。

【讨论】:

我知道上一页和下一页是什么。但是,用户可以导航到不同的屏幕,前提是他可以添加和删除显示的页面。这就是我所说的动态添加/删除的意思。 这不会改变我的答案。这个概念与滚动页面视图控制器的工作方式相反。选择另一个架构。 我还有一个想法。您的子视图控制器在进入视图之前实际上并没有完全配置自己;你会得到viewWillAppear。因此,如果这些都是同一个视图控制器类的所有实例,那么您可以执行配置。但无论哪种方式,您都需要摆脱保留的视图控制器列表;这是错误的。 好的,我会看看你提供的建议。谢谢! 过期更新:我遵循了您的第二个建议(分页水平滚动视图),它现在按预期工作。谢谢。【参考方案2】:

使用UIPageControllerscroll过渡风格的无崩溃主要规则:

1) 在调用setViewControllers 方法之前设置dataSource

2) 使用不带动画的setViewControllers 方法(animated: false)

3) 将 dataSource 设置为 nil 用于单页模式

4) 两页模式不允许循环

可以在my detailed answer找到稳定子类的完整Swift实现

可以在GitHub project找到初始代码和使用示例。

【讨论】:

以上是关于添加页面时 UIPageViewController 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Wordpress 在主题激活时创建页面 - 使用此功能添加子页面

添加页面时 UIPageViewController 崩溃

我在jsp页面上添加百度地图时,添加图片无法显示

在 Sharepoint 上打开新页面时添加弹出窗口

创建页面时向 WebPartPage 添加描述

没有可用的互联网连接时如何添加自定义错误页面