34,333
edits
Changes
→Creating the Data Model
The final step in creating the model is to add a method to the PageAppViewController.m file to add the HTML strings to the array and then call that method from viewDidLoad
<pre>
#import "PageAppViewController.h"
@interface PageAppViewController ()
@end
@implementation PageAppViewController
.
.
- (void) createContentPages
{
NSMutableArray *pageStrings = [[NSMutableArray alloc] init];
for (int i = 1; i < 11; i++)
{
NSString *contentString = [[NSString alloc]
initWithFormat:@"<html><head></head><body><br><h1>Chapter %d</h1><p>This is the page %d of content displayed using UIPageViewController in iOS 7.</p></body></html>", i, i];
[pageStrings addObject:contentString];
}
_pageContent = [[NSArray alloc] initWithArray:pageStrings];
}
.
.
- (void)viewDidLoad
{
[super viewDidLoad];
[self createContentPages];
}
</pre>
The application now has a content view controller and a data model from which the content of each page will be extracted by the data source methods. The next logical step, therefore, is to implement those data source methods. As previously outlined in Implementing a Page based iOS 7 Application using UIPageViewController, instances of the UIPageViewController class need a data source. This takes the form of two methods, one of which is required to return the view controller to be displayed after the currently displayed view controller, and the other the view controller to be displayed before the current view controller. Since the PageAppViewController is going to act as the data source for the page view controller object, these two methods, together with two convenience methods (which we will borrow from the Xcode Page-based Application template) will need to be added to the PageAppViewController.m file. Begin by adding the two convenience functions:
<pre>
#import "PageAppViewController.h"
@interface PageAppViewController ()
@end
@implementation PageAppViewController
- (ContentViewController *)viewControllerAtIndex:(NSUInteger)index
{
// Return the data view controller for the given index.
if (([self.pageContent count] == 0) ||
(index >= [self.pageContent count])) {
return nil;
}
// Create a new view controller and pass suitable data.
/*
ContentViewController *dataViewController =
[[ContentViewController alloc] init];
*/
UIStoryboard *storyboard =
[UIStoryboard storyboardWithName:@"Main"
bundle:[NSBundle mainBundle]];
ContentViewController *dataViewController =
[storyboard
instantiateViewControllerWithIdentifier:@"contentView"];
dataViewController.dataObject = _pageContent[index];
return dataViewController;
}
- (NSUInteger)indexOfViewController:(ContentViewController *)viewController
{
return [_pageContent indexOfObject:viewController.dataObject];
}
.
.
@end
</pre>
The viewControllerAtIndex method begins by checking to see if the page being requested is outside the bounds of available pages by checking if the index reference is zero (the user cannot page back beyond the first page) or greater than the number of items in the pageContent array. In the event that the index value is valid, a new instance of the ContentViewController class is created and the dataObject property set to the contents of the corresponding item in the pageContent array of HTML strings.
Since the view controller is stored in the storyboard file, the following code is used to get a reference to the storyboard and to create a new ContentViewController instance:
<pre>
UIStoryboard *storyboard =
[UIStoryboard storyboardWithName:@"MainStoryboard"
bundle:[NSBundle mainBundle]];
ContentViewController *dataViewController =
[storyboard
instantiateViewControllerWithIdentifier:@"contentView"];
</pre>
The indexOfViewController method is passed a viewController object and is expected to return the index value of the controller. It does this by extracting the dataObject property of the view controller and finding the index of the matching element in the pageContent array.
All that remains to be implemented as far as the data source is concerned are the two data source protocol methods which, in turn, make use of the two convenience methods to return the view controllers before and after the current view controller:
<pre>
- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerBeforeViewController:
(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:
(ContentViewController *)viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
- (UIViewController *)pageViewController:
(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:
(ContentViewController *)viewController];
if (index == NSNotFound) {
return nil;
}
index++;
if (index == [self.pageContent count]) {
return nil;
}
return [self viewControllerAtIndex:index];
}
</pre>
With the data source implemented, the next step is to create and initialize an instance of the UIPageViewController class.
== Initializing the UIPageViewController ==