I've been working on a simple test app to learn the ins and outs of the UIPageViewController. I have it working but I'm not convinced my execution is the best way. I hope some of you can point me in the right direction.
To get a basic understanding I used this tutorial as a starting point.
http://www.appcoda.com/uipageviewcontroller-storyboard-tutorial/
The tutorial creates an app that uses one viewController
for each of the pages presented by the UIPageViewController
. However I need to utilize the UIPageViewController to scroll thru pages that have completely different layouts. Therefore to take the tutorial a step further I created an master-detail application that uses the UIPageViewController in the detail view to display three different view controllers. I stuck with just displaying images and labels for this test app, but the app I am currently building has three viewControllers that will contain either a tableview, imageView and textViews, or some textFields.
Here is the storyboard for my test app.
![Storyboard](https://i1290.photobucket.com/albums/b538/7eleven3/ScreenShot2014-02-07at64412PM_zpsa64a19f6.png)
I use the DetailViewController
as the data source for the PageViewController
. In viewDidLoad
of the DVC I establish the labels and images that will be used in the three content view controllers firstViewController
, secondViewController
, and thirdViewController
in this manner.
if ([[self.detailItem description] isEqualToString:@"F14's"]) {
//Here the page titles and images arrays are created
_pageTitles = @[@"Grim Reapers", @"Breakin the Barrier!", @"Top Gun"];
_pageImages = @[@"F14_Grim.jpg", @"F14boom.jpg", @"F14_topgun.jpg"];
//Here I call a method to instantiate the viewControllers
FirstController *selectedController = [self viewControllerAtIndex:0];
SecondController *nextController = [self viewControllerAtIndex:1];
ThirdController *lastController = [self viewControllerAtIndex:2];
[_vc addObject:selectedController];
[_vc addObject:nextController];
[_vc addObject:lastController];
_vc1 = @[selectedController];
} else if ([[self.detailItem description] isEqualToString:@"F35's"]){
//code is above is repeated
Below is the method to instantiate the viewControllers
- (UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
if (([self.pageTitles count] == 0) || (index >= [self.pageTitles count])) {
return nil;
}
// Create a new view controller and pass suitable data.
if (index == 0) {
FirstController *fvc = [self.storyboard instantiateViewControllerWithIdentifier:@"FirstPageController"];
fvc.imageFile = self.pageImages[index];
fvc.titleText = self.pageTitles[index];
fvc.pageIndex = index;
if ([_vc count]) {
//Here I have to replace the viewController each time it is recreated
[_vc replaceObjectAtIndex:0 withObject:fvc];
}
return fvc;
} else if (index == 1) {
//Code is repeated for remaining viewControllers
The code in viewDidLoad
is one area I feel I am doing unnecassary work. I don't believe I need to instantiate all three view controllers upon loading the DVC, but I didn't know how else to provide an array for the UIPageViewControllerDataSource protocol methods (viewControllerBeforeViewController
and viewControllerAfterViewController
).
Here is the viewControllerBefore..
method.
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = [_vc indexOfObject:viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
//notice here I call my instantiation method again essentially duplicating work I have already done!
return [self viewControllerAtIndex:index];
}
In summary it seems that I am unnecassarily recreating the view controllers with every swipe from from one page to another. Is this just how the pageViewController works or have I way over complicated the process. Any input would be great!
SOLUTION
Matt suggested an incredibly simple solution in using identifiers. In my Storyboard i simply checked the box that uses my already implemented Storyboard identifier as the Restoration Identifier
![RestorationId](https://i1290.photobucket.com/albums/b538/7eleven3/ScreenShot2014-02-08at30842PM_zps3a8ff9e4.png)
Then in viewDidLoad
rather than creating an array of viewControllers, simply create an array of strings that match the restoration identifiers.
if ([[self.detailItem description] isEqualToString:@"F14's"]) {
_pageTitles = @[@"Grim Reapers", @"Breakin the Barrier!", @"Top Gun"];
_pageImages = @[@"F14_Grim.jpg", @"F14boom.jpg", @"F14_topgun.jpg"];
FirstController *selectedController = [self viewControllerAtIndex:0];
[_vc addObject:@"FirstPageController"];
[_vc addObject:@"SecondPageController"];
[_vc addObject:@"ThirdPageController"];
_vc1 = @[selectedController];
Finally to determine the index in the delegate methods do this rather than what I was doing before:
NSString * ident = viewController.restorationIdentifier;
NSUInteger index = [_vc indexOfObject:ident];
It now works without having to unnecessarily instantiate the view controllers.
As a last note if anyone is using exactly what I have here you can get rid of the following snippet from the viewControllerAtIndex:
method.
if ([_vc count]) {
//Here I have to replace the viewController each time it is recreated
[_vc replaceObjectAtIndex:0 withObject:fvc];
}