Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIPageViewController views messed up if user moves too quickly

I have a UIPageViewController that uses an integer to tell which page it is on. It works fine, but if the user quickly swipes several times to get to a page further back, the integer changes more quickly than the views do, and then the whole thing falls apart (the app thinks it is on page 7 when it could be displaying page 3). What am I doing wrong? Is there a different method I should use to tell where I am? Thanks.

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
    if (pageNumber == 0) {
        pageNumber++;
        NSLog(@"%i", pageNumber);
        Two *two = [[Two alloc] init];
        return two;
    } else if (pageNumber == 1) {
        pageNumber++;
        NSLog(@"%i", pageNumber);
        Three *three = [[Three alloc] init];
        return three;
    } else if (pageNumber >= 2) {
        return nil;
    } else {
        return nil;
    }
}
like image 577
Jack Humphries Avatar asked Mar 19 '12 21:03

Jack Humphries


1 Answers

The problem is that you're taking pageNumber for granted. UIPageViewController could only be asking for next viewController to preload it and you're already increasing pageNumber.

You were close when you noticed that "this also happens if a user grabs the edge of the page and starts to move it, but then puts it and back stays on the current page."

This method gets UIViewController for parameter and that is the only real reference you have.

Since you only have three pages one way to solve this would be:

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
    if ([viewController isKindOfClass: [One class]])
    {
        Two *two = [[Two alloc] init];
        return two;
    }
    else if ([viewController isKindOfClass: [Two class]])
    {
        Three *three = [[Three alloc] init];
        return three;
    }
    else
    {
        return nil;
    }
}

Note: this code is not the best solution - i'm just trying to point out that you shouldn't be simply increasing/decreasing pageNumber in viewControllerAfterViewController:/viewControllerBeforeViewController:

You could also [[... alloc ]init] viewControllers before all this and reduce initialization activity of viewControllers in UIPageViewControllerDataSource methods to loadView (if it's not loaded) at most. For example (abbreviated):

    ...
    if ([viewController isKindOfClass: [One class]])
    {
        //Two *two = [[Two alloc] init]; //called before and two is someone's property
        if (![two isViewLoaded]) [two loadView];
        return two;
    }
    else if ...

For more pages you could also try tagging viewControllers (during their initialization). Since UIViewController itself doesn't have a tag property you could probably use viewController.view.tag or sublcass UIViewController and add it a pageNumber property (this would probably be close to THE solution.

like image 99
Rok Jarc Avatar answered Sep 22 '22 12:09

Rok Jarc