2

Introduction

Hello world, I'm new to Objective C and I have been experimenting with the PageViewController. One problem I have encountered while making this app is changing the action of a button depending on the PageViewController. I have approached the situation in a multitude of ways.

Situation

I was trying to make a PageViewController to help a player choose a theme for a game, but in order to do this I need to figure out the answer to this question. I followed this tutorial except I got rid of the startWalkthrough button as it was unnecessary and I changed the self.pageViewController.view = CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.height - 200); as well as changing the NSArray _pageTitles = @[@"Theme 1", @"Theme 2", @"Theme 3", @"Theme 4"]; on the main view controller to allow more space for buttons and such.

I made a new button (chooseButton) and a label (themeTitles) just as an example to check whether or not the app realized which theme it was on the main view controller. I tried to use the following lines of code:

- (IBAction)chooseButton:(id)sender {
    if () {
    _themeTitles.text = @"You chose theme 1";
    }

    if () {
    _themeTitles.text = @"You chose theme 2";
    }

    if () {
    _themeTitles.text = @"You chose theme 3";
    }

    if () {
    _themeTitles.text = @"You chose theme 4";
    }
}

You may notice that the condition is blank. This is the part where I have tried a variety of things. This may include using properties from other header files, or properties declared in its own header file such as declaring PageContentViewController *pageContentViewController; and then saying if (pageContentViewController.pageIndex == 0) and so on until it equals 3, or saying if (pageContentViewController.titleText isEqual: @"Theme 1").

I also tried declaring AppDelegate *appDelegate; after importing it of course and making the UIPageControl public as a property and also making a currentPage property to say if (AppDelegate.pageControl.currentPage == 0) and so on.

I am going mad exhausting every option while they all end up displaying "You chose theme 1" on the interface for every current page it is on or it doesn't display anything at all.

Ultimately, the point is, what condition can I put in the if statement to get this thing working?

toriningen
  • 7,196
  • 3
  • 46
  • 68
ThatGuy
  • 119
  • 10

1 Answers1

1

UIPageViewController doesn't have a native idea of page number. It can tell you what view controllers are presently visible in the viewControllers property, but it's your job to map those to pages.

Why? Imagine a big, big book where each page is a view controller. It would be wasteful to keep all of these around in memory (the way a UINavigationController keeps around the current stack). So the UIPageViewController makes page array is virtual, only asking your datasource for view controllers relative to the current one.

What to do about it? There are a few articles in SO that make suggestions. My favorite is @EddieBorja's answer here. In a nutshell, assign your view controllers an index property (or pageNumber) property as you create them.

Once you've done that, your action method can look like this:

- (IBAction)chooseButton:(id)sender {
    // get the currently visible view controllers
    NSArray *viewControllers = self.myPageViewController.viewControllers

    // get the first visible one
    MyIndexKnowingViewController *myIndexKnowingVC = viewControllers[0];

    // branch on it's index
    if (myIndexKnowingVC.index == 0) {
        _themeTitles.text = @"You chose theme 1";
    } else (myIndexKnowingVC.index == 1) { 
    // etc.

    // if you have more than a few of these, consider a switch statement
    // or even better ...
    _themeTitles.text = [NSString stringWithFormat:@"You chose theme %d", myIndexKnowingVC.index+1];

Here's how I implement my datasource to set the index (and take advantage of it when answering the datasource protocol):

#pragma mark - Page vc datasource

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

    NSUInteger index = ((MyIndexKnowingViewController *)viewController).index;
    return (index)? [self viewControllerAtIndex:index-1] : nil;    
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {

    // note the +1
    NSUInteger index = ((MyIndexKnowingViewController *)viewController).index + 1;

    // define a max index that is one _greater_ then your number of pages
    return (index < MAX_INDEX)? [self viewControllerAtIndex:index] : nil;
}

- (MyIndexKnowingViewController *)viewControllerAtIndex:(NSUInteger)index {

    // assuming it's defined in a xib, otherwise, just alloc-init
    MyIndexKnowingViewController *childViewController = [[MyIndexKnowingViewController alloc] initWithNibName:@"MyIndexKnowingViewController" bundle:nil];
    childViewController.index = index;

    return childViewController;
}
Community
  • 1
  • 1
danh
  • 62,181
  • 10
  • 95
  • 136
  • Thanks for the answer, but it only shows two of the pages out of the four. It is better to just to have `return [self viewControllerAtIndex:index];` and without the `.index + 1`. Thanks anyway! @danh – ThatGuy Jul 27 '14 at 21:43
  • That index is the index of the passed vc. The purpose of the method is to return a vc with an index one greater than the passed vc. If MAX_INDEX is too low, that will keep it from working... hey come to think of it, my comment is wrong in there. MAX should be one greater not one less than the number of pages. Please see edit - sorry. – danh Jul 27 '14 at 23:10
  • I changed the max index and used your code again which ended up with the same problem... @danh – ThatGuy Jul 28 '14 at 01:18