1

I have a UIPageViewController (<UIPageViewControllerDataSource> delegate) that manages 3 UIViewController. To go from the second view to the third, i have to tap a button, otherwise the second view is the last visible page. Once on page 3, the user should be able to swipe to get back to 2, but not be able to swipe to return to 3 (the button is always necessary to get to page 3). This is part of the code:

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
    UIViewController *prevViewController = nil;
    if (viewController == self.P2ViewController) {
        prevViewController = self.P1ViewController;
    }
    if (viewController == self.P3ViewController) {
        [self pageViewController:pageViewController viewControllerAfterViewController:self.P2ViewController]; /*this doesn't work*/
        prevViewController = self.P2ViewController;
    }
    return prevViewController;
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
    UIViewController *nextViewController = nil;
    if (viewController == self.P1ViewController) {
        nextViewController = self.P2ViewController;
    }
    if (viewController == self.P2ViewController) {
        nextViewController = nil;
    }
    return nextViewController;
}

Then i have a custom UIViewController class where i have an IBAction and i pass the correct UIViewController with a static variable and a notification. Part of the code:

-(IBAction)goToPage:(NSNotification *)notification{
    /*some code*/
    [((UIPageViewController *)self.parentViewController) setViewControllers:viewControllersArray direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
}

The first time i go from page 1 to 2, the second page is the last one. Then i tap the button and i go to the third page correctly with the animation (the "animated bug" in UIPageViewController works good for me). Then the third view is the last one and i can go back to the second view, but when i go back no viewControllerAfterViewController: method is called and i can still go to the third page.

Instead, i want to go back to the second page leaving the second page as the last one again, deleting the third page from the cache every time i go back. I've tried with this code in my custom UIViewController class for the second page:

-(void)viewWillAppear:(BOOL)animated{
    [((UIPageViewController *)self.parentViewController) setViewControllers:@[myStaticViewController2] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
}

but it only works the second time i try to move back or forth from that page. It's also useless calling again the viewControllerAfterViewController inside the viewControllerBeforeViewController like i did. I hope i was clear, i can't find a solution to this problem.

Thanks in advance

David H
  • 40,852
  • 12
  • 92
  • 138
Val K.
  • 113
  • 1
  • 10
  • 1
    Create a small demo project and upload it, so people can try to get that to work as you wish. – David H Nov 21 '13 at 13:26
  • I've created a demo project: [This is the link](http://www16.zippyshare.com/v/80743718/file.html). I hope that this hosting will work – Val K. Nov 21 '13 at 15:16

1 Answers1

3

OK - think I found a way to make it work.

Put this in PageViewController, and add a declaration to the .h file:

// a button press is causing a move
- (void)moveToThirdController
{
    __weak PageViewController *pc = self;
    [self setViewControllers:@[self.P3ViewController] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL ret)
        {
            // second dispatch may be overkill
            dispatch_async(dispatch_get_main_queue(), ^
                {
                    // it seems setting no wipes the cache
                    [pc setViewControllers:@[pc.P3ViewController] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
                } );
        } ];
}

In you second view controller, I slightly modified what you ahd there:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    __weak P2ViewController *pc = self;
    dispatch_async(dispatch_get_main_queue(), ^
        {
            [((UIPageViewController *)self.parentViewController) setViewControllers:@[pc] direction:UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
        } );
}

The key was to constantly try to get the pageViewController to remove its cache with a second call where animated is NO.

It turns out this is a variation on the solution first posted here

Community
  • 1
  • 1
David H
  • 40,852
  • 12
  • 92
  • 138
  • Maybe i wasn't clear: i don't want page3 to be accessible sliding forward from page2, unless tapping the button on that page. Then, going back to page2, i want page3 to be deleted from the "UIPageViewController cache". – Val K. Nov 21 '13 at 15:49
  • 1
    Tell you what - you make the question clearer, I'll fix up the code to do what you want. – David H Nov 21 '13 at 15:55
  • Thank you a lot and excuse me for my poor english. However one solution could be a third `UIViewController` custom class for page3 and a `viewDidDisappear` customization with the `setViewControllers:direction:animated:completion:`, but in this case it will not work for a 3+ pages app (moving to the 4th page it will turn back to the 2nd), and i do have a lot of pages. – Val K. Nov 21 '13 at 16:16
  • Thank you! Thank you! I'm trying to understand how it works. I see that the `__weak` property & `dispatch_async`prevent `viewDidAppear` to enter a loop, it's the refresh i was searching for! So i tried to delete the `-(void)moveToThirdController{...}` because i already have an `IBAction` and in fact it does work. However it's true, it's a situation similar to the `UIPageViewController` bug one. Excellent, thank you very much! – Val K. Nov 21 '13 at 18:52
  • Good design practice would be to enclose the internals of how the page controller is being used to within that class, and expose methods to "drive" it. Even the code done in viewController2 should be a method there. In two years, if UIPageController changes, how will you ever figure out what you did if the code is strewn around all your classes. Its what I'd do in any case, since I've had to look at my old code years later and try to figure out what the h*ll I was trying to do... – David H Nov 21 '13 at 19:53
  • This worked amazingly for me. I was wondering why the "viewControllerBeforeViewController" wasn't being called on my datasource and didn't even realize that iOS was caching the previous screen. Seems really weird that it clears the cache when you transition without an animation, makes one wonder why they have that cache in the first place. Thanks a lot for the answer, this was killing me. – Heckman Jan 03 '15 at 06:41