pageViewController setViewControllers crashes with "Invalid parameter not satisfying: [views count] == 3"

I ran into the same problem, and was able to solve it using a tip from this answer https://stackoverflow.com/a/20973822/3757370. Simply placing the setViewControllers:direction:animated:completion: code inside of a dispatch_async block on the main queue fixed it for me. For you this would look like

dispatch_async(dispatch_get_main_queue(), ^{
    [self.pageViewController setViewControllers:@[ [self.storyboard instantiateViewControllerWithIdentifier:_pageStoryBoardIDs[0]] ]
                                     direction:UIPageViewControllerNavigationDirectionReverse
                                     animated:YES completion:nil];
});

Hope it helps!


Ran into this exact same issue. Solved it by setting the first content controller explicitly on the UIPageViewController when it is first loaded (ie: inside 'viewDidLoad').

// create first page
UIViewController* firstContentPageController = [self contentControllerAtIndex: 0];
[_paginationController
    setViewControllers: @[firstContentPageController]
    direction: UIPageViewControllerNavigationDirectionForward
    animated: NO
    completion: nil];

where 'contentControllerAtIndex:' is a simple helper method that creates a content controller. I also use it within the two delegate methods in order to return the appropriate controller for a given page.

- (UIViewController*)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
    NSInteger index = (NSInteger)((MyContentController*)viewController).pageIndex;

    return [self contentControllerAtIndex: index - 1];
}


- (UIViewController*)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
    NSInteger index = (NSInteger)((MyContentController*)viewController).pageIndex;

    return [self contentControllerAtIndex: index + 1];
}


- (MyContentController*)contentControllerAtIndex: (NSInteger)index {
    if (index < 0 || _pagesContent.count <= index)
        return nil;

    // create view controller
    MyContentController* contentController = [self.storyboard instantiateViewControllerWithIdentifier: @"MyContentController"];
    contentController.pageIndex = index;
    contentController.content = [_pagesContent objectAtIndex: index];

    return contentController;
}

The reason for this is that the UIPageViewControllerDataSource protocol was designed to only have methods for pulling the previous/next content controller, as opposed to pulling a single controller at a particular index. It's an odd design decision, but the caveat is that instead of being called by Cocoa when the component is first loaded you have to manually set its starting state. Poor framework design here IMHO.


Well it's 2018 and the bug is still around. I tried all the solutions above, but none worked for me. And after many tries, setting the animation parameter to false, was what worked for me in swift 4

let myViewController : UIViewController = orderedViewControllers[vcIndex]
setViewControllers([myViewController], direction: .forward, animated: false, completion: nil);

Then it was just a matter of setting a custom transition. Hope it helps others in the same situation.

Tags:

Xcode