Approval Error in UIPageViewController

I have an approval error in the 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 do not know why this error occurs. Any clues about what causes it, or how to debug it?

+7
ios uikit uiviewcontroller uiview uipageviewcontroller
source share
5 answers

This happened to me when I had text fields in the controller for children and did not reject the keyboard to scroll to the next controller. If this is the case, just add endEditing in the action where you programmatically change your controller or scroll through the delegate method scrollViewDidScroll for pageViewController

0
source share

Move the pageViewController.setViewControllers function pageViewController.setViewControllers inside the DispatchQueue.main.async block if you do this in code.

I don't know why this works, but it worked for me. For reference.

0
source share

This happens when your UIPageViewControllerTransitionStyle set to scroll instead of pageCurl .

Do you dynamically create View Controllers and set them to UIPageViewController? In this case, you must make sure that the second call to setViewControllers is called after the first animation is completed due to an error in UIKit. Delayed posting is a quick and dirty fix, although this is not a good practice.

More details here.

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

0
source share

A direct way to run this statement is to use a loop source for the UIPageController defined by the scroll style.

When a source contains two pages, each of them is the previous and next for the other. If you swipe the UIPageController screen containing two pages, and then try to set the source to 3 pages, you will get the above statement with the guarantee that the UIPageControllerDataSource methods before / after allow a cyclic transition in the case of 2 pages.

Basic rules without crashing using the UIPageController with scroll scroll:

1) set dataSource before calling setViewControllers method

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

3) set dataSource to zero for single page mode

4) do not allow cycles for 2-page mode

All of these recommendations together make the 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 } } 

General examples of implementation and use can be found in the GitHub project .

0
source share

For me, the problem was using self.pageViewController as a member of the current view controller instead of pageViewController as the parameter obtained in the didFinishAnimating delegate didFinishAnimating .

0
source share

All Articles