In my code I do sometimes "reset" UIPageViewController by using the construct as given below:
id vc = [pageViewController.viewControllers firstObject];
__weak UIPageViewController *pvc = pageViewController;
__weak MyViewController *weakSelf = self; // UIViewController subclass which is hosting pageViewController
pageViewController.dataSource = nil;
[pageViewController setViewControllers: @[ [[UIPageViewController alloc] init] ]
direction: UIPageViewControllerNavigationDirectionForward
animated: NO completion: ^(BOOL completed) {
[pvc setViewControllers: @[ vc ] direction: UIPageViewControllerNavigationDirectionForward
animated: NO completion: ^(BOOL completed) {
pvc.dataSource = weakSelf;
}];
}];
This works perfectly almost all the time, but recently, when I was fast swiping pages back and forth, the app has crashed with NSInternalInconsistencyException caused in:
*** Assertion failure in -[UIPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:], /SourceCache/UIKit/UIKit-3318.16.14/UIPageViewController.m:1875
The crash was caused by reset code being invoked from viewWillLayoutSubviews method of a view controller which is hosting UIPageViewController. The reason was: "No view controller managing visible view: (here goes my custom view)". This custom view is only created within vc instances - view controllers that are passed to UIPageViewController. So I don't think it's possible for them to exist without this view controller. I am not able to reproduce this issue, but I believe it can happen again, at random.
What can be the real reason for this happening?
Is this a bug in UIKit?
Are there any workarounds?
First of all, setViewControllers:direction:animated:completion: is for you to set all the view controllers that will be visible after the animation has finished: sending that an array that consists solely of a freshly allocated UIPageViewController means that the original pageViewController object will just be showing a brand new UIPageViewController and no content view controllers, which I'm pretty sure is very bad and really not what you intended.
The array should consist of whichever view controllers you want to be showing next.
Secondly, is your UIPageViewController set with a page transition style of UIPageViewControllerTransitionStyleScroll?
If so, there is indeed a bug in UIKit that sometimes causes this exception; I *think* it can be prevented by making sure you don't initiate a second call to setViewControllers:direction:animated:completion: until the first has completed, but I've yet to test the theory.