UIPageViewController中的断言失败 [英] Assertion failure in UIPageViewController

查看:193
本文介绍了UIPageViewController中的断言失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在UIPageViewController中断言失败.

I have an Assertion Failure in UIPageViewController.

Assertion failure in -[UIPageViewController _flushViewController:animated:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.60.12/UIPageViewController.m
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason:
'Don't know about flushed view <UIView: 0x15a5bff30; frame = (0 0; 768 903); autoresize = W+H; layer = <CALayer: 0x15a5bfc30>>'
*** First throw call stack:
(0x181ebedb0 0x181523f80 0x181ebec80 0x182844154 0x1877a1c40 0x1877a1da8 0x18784e9c4 0x18784ebfc 0x187852318 0x18784dd98 0x1870101e4 0x1849a2994 0x18499d5d0 0x1870270a4 0x10028b620 0x100348b78 0x100379f54 0x100168878 0x18733d568 0x1870330b4 0x1870f1a00 0x18733e71c 0x1870f832c 0x18703536c 0x18700f7ac 0x18700ed40 0x18700eba8 0x1873283b4 0x18700d5e8 0x18784ebd4 0x187852318 0x18784df3c 0x1871db550 0x1871daf6c 0x101c9b768 0x1849f0234 0x1849f00e8 0x182135e54 0x181e5d030 0x181e757d4 0x181e74f0c 0x181e72c64 0x181d9cc50 0x183684088 0x18707e088 0x10033b200 0x18193a8b8)
libc++abi.dylib: terminating with uncaught exception of type NSException

我不知道为什么会发生此错误.关于它是什么原因或如何调试的任何线索?

I don't know why this error is occurring. Any clues on what's causing it or how to debug it?

推荐答案

遇到此断言的直接方法是将循环源用于使用滚动过渡样式定义的UIPageController.

The direct way to run into this assert is to use cycled source for UIPageController defined with scroll transition style.

当源包含两个页面时,每个页面是上一页,下一页是另一页.如果您滑动包含两个页面的UIPageController,然后尝试将源设置为3个页面,则将得到上述声明,并保证UIPageControllerDataSource之前/之后方法允许在2页的情况下进行循环转换.

When the source contains two pages each one is the previous and the next for another one. If you swipe UIPageController containing two pages and then try to set source with 3 pages you will get the assertion mentioned above with guarantee assuming that UIPageControllerDataSource before/after methods allow cycled transition in case of 2 pages.

使用UIPageController进行滚动过渡时实现无崩溃的主要规则:

The main rules of crash-free using UIPageController with scroll transition:

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

1) set dataSource before calling setViewControllers method

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

2) use setViewControllers method without animation (animated: false)

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

3) set dataSource to nil for single page mode

4)不允许在2页模式下循环

4) don't allow cycles for 2-page mode

所有这些建议一起使UIPageController绝对稳定.

All these recommendations together make UIPageController absolutely stable.

import UIKit

/// Convenient subclass of UIPageViewController
@objc class AMPageViewController: UIPageViewController {

    /// Turn on/off PageControl at the bottom
    @objc var showPageControl: Bool = true

    /// Array of all viewControllers
    @objc var source: [UIViewController]? {

        didSet {
            let count = source?.count ?? 0
            if count > 0 {
                dataSource = count > 1 ? self : nil
            }
            else {
                dataSource = nil
                delegate = nil
            }
        }
    }

    /// Index of the current viewController from source
    @objc var pageIndex: Int {

        get {
            var currentPageIndex: Int = 0
            if let vc = viewControllers?.first, let source = source, let pageIndex = source.index(of: vc) {
                currentPageIndex = pageIndex
            }

            return currentPageIndex
        }

        set {
            guard newValue >= 0, let source = source, newValue < source.count else { return }

            let vc = source[newValue]
            let direction: UIPageViewControllerNavigationDirection = newValue < pageIndex ? .reverse : .forward

            setViewController(vc, direction: direction)
        }
    }

    override weak var delegate: UIPageViewControllerDelegate? {

        get { return super.delegate }

        set {
            if source?.count ?? 0 > 0 {
                super.delegate = newValue
            }
            else {
                super.delegate = nil
            }
        }
    }

    /// Initializer in scroll-mode with interPageSpacing
    @objc init(navigationOrientation: UIPageViewControllerNavigationOrientation = .horizontal, interPageSpacing: Int = 0) {

        let options = (interPageSpacing > 0) ? [UIPageViewControllerOptionInterPageSpacingKey : 5] : nil

         super.init(transitionStyle: .scroll, navigationOrientation: navigationOrientation, options: options)
     }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    /// Set viewcontroller by index from source
    @objc func setPageIndex(_ index: Int, completion: ((Bool) -> Void)? = nil) {

        guard index > 0, let source = source, index < source.count else { return }

        let vc = source[index]
        let direction: UIPageViewControllerNavigationDirection = index < pageIndex ? .reverse : .forward

        setViewController(vc, direction: direction, completion: completion)
    }


    private func setViewController(_ viewController: UIViewController, direction: UIPageViewControllerNavigationDirection = .forward, completion: ((Bool) -> Void)? = nil) {

        super.setViewControllers([viewController], direction: direction, animated: false, completion: completion)
    }
}

extension FFPageViewController: UIPageViewControllerDataSource {

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {

        guard let source = source, let index = source.index(of: viewController) else { return nil }

        let count = source.count

        if count == 2, index == 0 {
            return nil
        }

        let prevIndex = (index - 1) < 0 ? count - 1 : index - 1

        let pageContentViewController: UIViewController = source[prevIndex]

        return pageContentViewController
    }


    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {

        guard let source = source, let index = source.index(of: viewController) else { return nil }

        let count = source.count

        if count == 2, index == 1 {
            return nil
        }

        let nextIndex = (index + 1) >= count ? 0 : index + 1

        let pageContentViewController = source[nextIndex]

        return pageContentViewController
    }


    func presentationCount(for pageViewController: UIPageViewController) -> Int {

        return showPageControl ? (source?.count ?? 0) : 0
    }


    func presentationIndex(for pageViewController: UIPageViewController) -> Int {

        guard showPageControl else { return 0 }

        return pageIndex
    }
}

可以在 GitHub项目中找到整个实现和用法示例.

The overall implementation and usage examples one can find at GitHub project.

这篇关于UIPageViewController中的断言失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆