2

I am making an iOS application that has a UIPageViewController that is loaded with a default page if there aren't any others added yet, and a user can add pages as he progresses through the app. However, the initial view never changes as others are added.

I've tried the answers from these questions:
Is it possible to Turn page programmatically in UIPageViewController?
Changing UIPageViewController's page programmatically doesn't update the UIPageControl
Removing a view controller from UIPageViewController
Refresh a UIPageViewController

None of them work for me. The view still remains at the initial page until I reload the application, after which, the pages show fine, and I can add as many as I want.

This is the code I have for making the PageView and the pages

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.pageController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];

    self.pageController.dataSource = self;
    [[self.pageController view] setFrame:[[self pageControllerView] bounds]];

    UIViewController *initialViewController = [self viewControllerAtIndex:0];

    __block Page1ViewController *blocksafeSelf = self;

    // This doesn't work either... :(
    void (^completionBlock)(BOOL) = ^(BOOL finished)
    {
        // It seems that whenever the setViewControllers:
        // method is called with "animated" set to YES, UIPageViewController precaches
        // the view controllers retrieved from it's data source meaning that
        // the dismissed controller might not be removed. In such a case we
        // have to force it to clear the cache by initiating a non-animated
        // transition.
        usleep(1);
        dispatch_async(dispatch_get_main_queue(), ^(){
            [blocksafeSelf.pageController setViewControllers:@[initialViewController]
                                      direction:UIPageViewControllerNavigationDirectionForward
                                       animated:NO
                                     completion:nil];
        });
    };

    [self.pageController setViewControllers:@[initialViewController]
                              direction:UIPageViewControllerNavigationDirectionForward
                               animated:YES
                             completion:completionBlock];

    [self addChildViewController:self.pageController];
    [[self view] addSubview:[self.pageController view]];
    [self.pageController didMoveToParentViewController:self];
}

- (void)reloadViews
{
    [[self childViewControllers] makeObjectsPerformSelector:@selector(removeFromParentViewController)];
    [[self.view subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

    [self.pageController willMoveToParentViewController:nil];
    [self.pageController removeFromParentViewController];
    [self.pageController.view removeFromSuperview];
    self.pageController = nil;
    self.pageController = [[UIPageViewController alloc] init];

    [self.view setNeedsDisplay];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
    NSUInteger index = ((SomethingViewController *)viewController).index;
    index++;

    if (index >= [Settings somethings].count)
    {
        return nil;
    }

    return [self viewControllerAtIndex:index];
}

- (UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
    UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Storyboard_iPhone"
                                              bundle:nil];
    if ([Settings somethings].count == 0 && index == 0)
    {
        NoSomethingViewController *vc = [sb instantiateViewControllerWithIdentifier:@"NoSomethingViewController"];
        vc.index = index;
        return vc;
    }

    SomethingViewController *childViewController = [sb instantiateViewControllerWithIdentifier:@"SomethingViewController"];
    childViewController.something = [[Settings somethings] somethingAtIndex:index];
    childViewController.index = index;

    return childViewController;
}

When a new page should be created, by adding a something in the somethings array, I call reloadViews from the View controller that did the adding of the something. The code then hits the second part of viewControllerAtIndex, but that is not shown on the page that I see on the phone, as I still see the NoSomethingViewController and it's view.

If you need more code, I'll provide.

Community
  • 1
  • 1
Reapo
  • 109
  • 2
  • 9
  • what you are trying to do? you are trying to scroll and in UIPageIndicator page is not changing or you are trying to add extra page once UIPageViewController has loaded the page? – Gyanendra Jul 03 '14 at 10:29
  • I am trying to reload page view controller to show a different page, when I add a `something` – Reapo Jul 03 '14 at 10:33
  • I don't think you can reload page view controller after it is loaded. One thing you can do is if some thing is getting changed then remove the page View controller from superview and add it again so dynamic pages will be loaded if some thing will change. – Gyanendra Jul 03 '14 at 13:02
  • I do at the beginning of the `viewDidLoad` method. if the page controller already exists, remove it; recreate it. It doesn't do anything. – Reapo Jul 03 '14 at 13:16
  • Yes but when you have to add new pages in page view controller at that time also remove it from superview and add the page view controller again, by doing this pageviewController delegate will be called again and in pageviewcontroller number of pages will automatically get refreshed. – Gyanendra Jul 03 '14 at 13:23
  • Ok, I've tried adding `[self.pageController.view removeFromSuperview]` to the check, it didn't do anything, and now it seems that `self.pageViewController` is always nil when I call viewDidLoad again, so the code inside the first `if` in the code I linked never gets called. Will try to fix that, and come back with an update. – Reapo Jul 04 '14 at 08:50
  • Updated `reloadViews` function. Still no luck. – Reapo Jul 04 '14 at 09:03

4 Answers4

3

add the following code in the pageViewController viewWillAppear method

dataSource = self

and in the viewWillDisappear add

dataSource = nil

this will force the pageViewController to reload its dataSource

Ahmed Onawale
  • 3,992
  • 1
  • 17
  • 21
0

To show the current dot, dont forget you have to update the page indicator

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController

Example how to update your UIPageControl indicator https://stackoverflow.com/a/22576250/3897011

Community
  • 1
  • 1
0

After a long time and after wasting a support ticket with Apple, I decided to go with another approach.

In my Storyboard I created 2 different navigation controllers, one for each case (if there are somethings and if there aren't any), and I have an initial view Controller that, on viewDidAppear, instantiates one of the two and presents it. This way, I make sure that the entire navigation controller gets reloaded correctly.

UINavigationController *nc;

if ([Settings somethings].count)
{
    nc = [self.storyboard instantiateViewControllerWithIdentifier:@"NavigationController"];
}
else
{
    nc = [self.storyboard instantiateViewControllerWithIdentifier:@"NoSomethingNavigationController"];
}

self.nc = nc;

[self presentViewController:nc animated:NO completion:nil];
Reapo
  • 109
  • 2
  • 9
-1

In order to reload UIPageViewController you can use the following code:

[self.pageController setViewControllers:@[yourCurrentController]
                                      direction:UIPageViewControllerNavigationDirectionForward
                                       animated:NO
                                     completion:nil];

Also please implement

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController

method.

Sviatoslav Yakymiv
  • 7,887
  • 2
  • 23
  • 43
  • Please check the code. I already have `[self.pageController setViewControllers:@[yourCurrentController] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];` And the program wouldn't run if I didn't have viewControllerBeforeViewController. It's just the default one (if index > 0 index--), so I didn't copy it into the question – Reapo Jul 04 '14 at 09:14
  • Yes. In viewDidLoad method. You should use it again when you want to reload UIPageViewController. – Sviatoslav Yakymiv Jul 04 '14 at 09:16
  • when I call reloadViews, the viewDidLoad method gets called again. – Reapo Jul 04 '14 at 09:18
  • Odd. BTW you should call [super viewDidLoad] – Sviatoslav Yakymiv Jul 04 '14 at 09:22
  • Yes, I know it's odd, and I haven't been able to figure it out myself, that's why I'm asking here. `[super viewDidLoad]` has been added to the question. – Reapo Jul 04 '14 at 09:26