Reputation: 855
In the iOS 11 app I'm developing (using Swift 4), I need to dynamically add pages to a UIPageViewController
. However, in some circumstances, I receive the following crash error (NSInternalInconsistencyException
):
2017-11-27 14:55:54.787260+0000 MyApp[380:79434] *** Assertion failure in -[UIPageViewController _flushViewController:animated:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3698.21.8/UIPageViewController.m:2124
2017-11-27 14:55:54.791022+0000 MyApp[380:79434] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Don't know about flushed view <UIView: 0x12dd48ac0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x1c003c280>>'
I am very new to iOS development, so I'm sorry if the answer is obvious, but I'm having a hard time finding the root cause for the crash. The logged message isn't being very helpful either...
This is the code I'm using to add pages:
//Inflate the view controller
let viewController = newViewController(param: someParam )
//Add it to the view controllers pool
viewControllersOrdered.insert(viewController, at: getInsertionIndex(param: someOtherParam) )
//Add it to the pageViewController
pageViewController.setViewControllers([viewController], direction: .forward, animated: false, completion: nil)
//Force cache to be cleared
pageViewController.dataSource = nil;
pageViewController.dataSource = self;
The getInsertionIndex
function is working correctly, that is not the source of the crash.
Upvotes: 1
Views: 4910
Reputation: 10096
The main rules of crash-free using UIPageController
with scroll
transition style:
1) set dataSource
before calling setViewControllers
method
2) use setViewControllers
method without animation (animated: false
)
3) set dataSource
to nil for single page mode
4) don't allow cycles for 2-page mode
One can find full Swift
realisation of a stable subclass at my detailed answer
The initial code and usage examples one can find at GitHub project.
Upvotes: 2
Reputation: 535566
In the iOS 11 app I'm developing (using Swift 4), I need to dynamically add pages to a UIPageViewController.
It sounds like what you mean is: you do not know what the next / previous view controller will be until the user actually tries to "turn the page". In that case, a scrolling UIPageViewController is not a good fit for your architecture (because, as you have already figured out, it precaches the next and previous pages). You have two choices:
Use a page-curl UIPageViewController. It doesn't precache its pages, so you are not called upon to make a decision until the user actually asks to turn the page.
Don't use a UIPageViewController at all; use a paging horizontal scroll view and manage the content view yourself.
Also, if you're using a UIPageViewController, in no case should you also be holding a retained list of child view controllers. That is the job of the UIPageViewController. Your job is merely to supply the next or previous view controller, which you should create on demand and at no other time, and release it into the UIPageViewController's sole control.
Upvotes: 6