【问题标题】:Assertion failure in UIPageViewControllerUIPageViewController 中的断言失败
【发布时间】:2017-08-07 14:36:49
【问题描述】:

我在 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

我不知道为什么会出现这个错误。有关导致它的原因或如何调试它的任何线索?

【问题讨论】:

  • 什么是刷新视图控制器?
  • 我对flushViewController一无所知...我没有使用flushViewController..我认为UIPageViewController内部使用flushViewController方法
  • 你的视图是什么样的 你用它做什么?
  • 我也遇到了类似的问题,这个问题解决了吗?
  • @kformeck 显然不是。创建了一个赏金。

标签: ios uiview uiviewcontroller uikit uipageviewcontroller


【解决方案1】:

遇到此断言的直接方法是为UIPageController 使用滚动转换样式定义的循环源。

当源包含两页时,每一页是前一页,后一页是另一页。如果您滑动包含两页的UIPageController,然后尝试将源设置为三页,您将得到上述断言,并保证假设UIPageControllerDataSource before/after 方法允许在两页的情况下循环转换。

使用UIPageController带滚动过渡的无崩溃主要规则:

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

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

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

4) 两页模式不允许循环

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

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 project找到整体实现和使用示例。

【讨论】:

  • 如果你想要动画怎么办?
【解决方案2】:

UIPageViewControllertransition 时,其中的 ViewController(ex: UITableViewController) transition 会导致崩溃。

就我而言(崩溃):

第一步

self.pageViewController.setViewControllers([self.tableViewController2], direction: .forward, animated: true, completion: nil)

第二步

UIPageViewController 转换时滚动tableView。

我的解决方案

(禁用滚动目标视图控制器和当前视图控制器)

self.tableViewController1.tableView.isScrollEnabled = false
self.tableViewController2.tableView.isScrollEnabled = false
self.pageViewController.setViewControllers([self.tableViewController2], direction: .forward, animated: true, completion: { _ in
    self.tableViewController1.tableView.isScrollEnabled = true
    self.tableViewController2.tableView.isScrollEnabled = true
})

【讨论】:

    【解决方案3】:

    当我在子控制器中有文本字段并且在滚动到下一个控制器时没有关闭键盘时,这也发生在我身上。如果是这种情况,只需在以编程方式更改控制器的操作中添加 endEditing,或者在 pageViewController 的 scrollViewDidScroll 委托方法上滚动

    【讨论】:

      【解决方案4】:

      如果您在代码中执行此操作,请将您的 pageViewController.setViewControllers 函数调用移动到 DispatchQueue.main.async 块中。

      我不知道它为什么有效,但它对我有效。 For reference.

      【讨论】:

        【解决方案5】:

        当您的 UIPageViewControllerTransitionStyle 设置为 scroll 而不是 pageCurl 时,会发生这种情况。

        您是否在动态创建视图控制器并在 UIPageViewController 上设置它们?在这种情况下,由于 UIKit 中的错误,您必须确保在第一次完成动画后调用 setViewControllers 的第二次调用。延迟调度是一种快速而肮脏的解决方法,尽管它不是一个好习惯

        这里有更多细节。

        https://forums.developer.apple.com/thread/6554

        【讨论】:

          【解决方案6】:

          对我来说,问题是使用self.pageViewController 作为当前视图控制器的成员,而不是使用pageViewController 作为在didFinishAnimating 委托方法中获得的参数。

          【讨论】:

            猜你喜欢
            • 2011-05-27
            • 2012-08-01
            • 2015-09-01
            • 2012-09-26
            • 2015-09-26
            • 2011-09-08
            相关资源
            最近更新 更多