UIPageViewController中的断言失败

51

在 UIPageViewController 中快速切换选项卡时,应用程序会在该行崩溃。

[UIPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:]

出现错误,断言失败并终止应用程序,原因是未捕获的异常'NSInternalInconsistencyException',原因是没有视图控制器管理可见视图。

以下为错误日志

*** Assertion failure in -[UIPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:], /SourceCache/UIKit/UIKit-3318.0.1/UIPageViewController.m:1875
2014-09-29 11:34:00.770 Wowcher[193:9460] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'No view controller managing visible view <UIView: 0x1783fa80; frame = (0 0; 320 416); autoresize = W+RM+H+BM; layer = <CALayer: 0x17898540>>'
*** First throw call stack:
(0x219fbf87 0x2f15ac77 0x219fbe5d 0x226cb2c9 0x253f9fff 0x2546f8d3 0x2546f6b7 0x2546c2b9 0x254700db 0x25470f97 0x2546d037 0x24ea925f 0x2500a589 0x24ff7eef 0x24ea677d 0x252b8c81 0x24e70105 0x24e6e07f 0x24ea4b6d 0x24ea443d 0x24e7acc5 0x250ee513 0x24e79707 0x219c2807 0x219c1c1b 0x219c0299 0x2190ddb1 0x2190dbc3 0x28c99051 0x24ed9a31 0xd950b 0xca6e0)
libc++abi.dylib: terminating with uncaught exception of type NSException

提前感谢


请查看以下网址:https://dev59.com/aGkv5IYBdhLWcg3wdQrm - LS_
我查看了您提供的参考链接,但仍然遇到相同的问题。 - Brjv
7个回答

30
所以我的解决方案是添加一个 BOOL 变量来跟踪我的动画状态。因此,在设置新的 ViewController 之前,我也会修改它:

因此我的解决方法是添加一个 BOOL 变量来跟踪我的动画状态。所以在设置新的 ViewController 之前,我也会对其进行修改:

if (!_transitionInProgress) {
    _transitionInProgress = YES;
    [self.pageController setViewControllers:@[viewController] direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:^(BOOL finished) {
        _transitionInProgress = !finished;
    }];
}
所以在设置新的视图控制器之前,我会等待我的动画完成。在我的情况下,用户可以按一些按钮以切换页面。这也防止他们过快地浏览页面,使动画始终平滑而美观。

1
这对我起作用了,我还允许用户在视图上滑动以更改分页,因此我在UIPageViewControllerDelegate方法willTransitionToViewControllersdidFinishAnimating中添加了相同的状态跟踪,以防止重叠的点击和滑动。 - johnrechd
这非常有帮助,但是一旦我将标志设置为staticprivate static var transitionInProgress = false,我得到了更好的结果。以这种方式调用它<viewControllerClassName>.transitionInProgress。我相信这可以改善处理当用户试图快速来回滑动时出现的竞态条件。 - Matt Bearson

16

这是UIPageViewController在滚动模式下内部实现的一个bug。它会在页面视图控制器正在进行转场动画时发生。我最终做的是阻止UI允许快速滚动多个页面。我有两个按钮,向左和向右,它们可以使页面视图控制器滚动到上一个或下一个页面控制器。当有动画正在进行时,我禁用按钮操作。页面视图控制器的代理会告诉你何时禁用UI功能以及何时在所有动画停止后重新启用它。


4
我也遇到了这个问题,但问题在于我无法持续重现它,但从崩溃日志中可以看出问题确实存在。
我有一个页面视图控制器,允许用户滑动并且视图可以程序化地滚动。应用程序有时会在您刚进入屏幕时崩溃,但在下一次尝试中,它正常工作,所以这有点疯狂。即使我放置了修复,我也无法确定它是否有效,因为我无法重现它。看起来下面的代码应该解决它(取自从UIPageViewController中删除视图控制器),至少使用此代码屏幕行为更好。如果我能得到一些注入崩溃的方法,以便我可以验证修复,我将不胜感激。
- (void) setViewControllers:(NSArray*)viewControllers direction:(UIPageViewControllerNavigationDirection)direction animated:(BOOL)animated completion:(void (^)(BOOL))completion {

    if (!animated) {
        [super setViewControllers:viewControllers direction:direction animated:NO completion:completion];
        return;
    }

    [super setViewControllers:viewControllers direction:direction animated:YES completion:^(BOOL finished){

        if (finished) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [super setViewControllers:viewControllers direction:direction animated:NO completion:completion];
            });
        } else {
            if (completion != NULL) {
                completion(finished);
            }
        }
    }];
}

1
添加以下内容后,程序崩溃问题得到了解决(之前约80%的情况下会出现这个问题)。 - Alexandre G
1
@AlexandreG 我也是。 - Nabeel Ahmed
它仍然发生,但不一定是持续的。 - Duan Nguyen
崩溃仍在发生。 - Pedro Paulo Amorim

1
我也遇到了同样的情况,我的应用程序有滑动和上一页/下一页按钮来前后导航。为了解决这个问题,请在初始化时分配一个本地布尔变量并将其设置为true(假设是私有变量canScroll:Bool = true),然后在导航方法的第一行中使用guard检查条件,然后在setViewcontroller方法之前将布尔值设置为false。在动画完成时,将相同的布尔值设置为true,以便在视图控制器正在过渡时执行滑动操作时,guard语句检查canScroll是否为true,如果不是,则返回。这就是如何避免分页中的崩溃问题,以下是我的下一步操作代码。
 @IBAction func nextAction(_ sender: Any) {
            guard canScroll == true else { return } //check condition
            guard featureCount > 0 else { return }
    guard let index = self.viewControllerAtIndex(indexRow) else { return }
            let startingViewController: OnBoardModelViewController = index
            canScroll = false 
            pageViewController?.setViewControllers([startingViewController],
                                                   direction: UIPageViewControllerNavigationDirection.forward,
                                                   animated: true,
                                                   completion: {_ in
                                                    self.canScroll = true
            })
}

1

这里有一个非常好的讨论:

从UIPageViewController中删除视图控制器

被接受的答案讨论了以下内容:

"不知道为什么会发生这种情况,我回溯了一下,最终采用了Jai的答案作为解决方案,创建了一个全新的UIPageViewController,将其推到UINavigationController中,然后弹出旧的。很丑陋,但它可以运行--大部分时间。我发现我仍然偶尔从UIPageViewController得到断言失败,如下所示:

  • - [UIPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:]中的断言失败, /SourceCache/UIKit_Sim/UIKit-2380.17/UIPageViewController.m:1820 $1 = 154507824 No view controller managing visible view >

应用程序崩溃了。为什么?搜索后,我发现了这个我之前提到的其他问题,特别是被采纳的答案,支持我的最初想法,即简单地调用setViewControllers: animated:YES,然后在完成后立即使用相同的视图控制器调用setViewControllers: animated:NO来重置UIPageViewController,但它缺少一个要素:在主队列上回调该代码!以下是代码:


我会尝试在今晚美国时间开发一个示例。现在要去工作了。 - Steve Rosenberg

1

当我将UIPageViewController作为子视图控制器使用时,我遇到了相同的问题。

这个问题是由于子UIPageViewController的尺寸不是圆形造成的。只要我确保它被正确地圆化,崩溃就消失了。


0
我通过在我的UIPageViewController子类上设置edgesForExtendedLayout = UIRectEdgeNone来解决了这个问题:
- (instancetype)initWithTransitionStyle:(UIPageViewControllerTransitionStyle)style navigationOrientation:(UIPageViewControllerNavigationOrientation)navigationOrientation options:(NSDictionary<NSString *,id> *)options
{
    self = [super initWithTransitionStyle:style navigationOrientation:navigationOrientation options:options];

    self.edgesForExtendedLayout = UIRectEdgeNone;

    return self;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接