Jobs Jobs - 4 months ago 188
Swift Question

Go to the next Page programmatically within a UIPageViewController

I have a rootViewController which is basically my pageViewController which implements all the page controller protocol functions. I have already successfully implemented the whole pageViewController with a pageControl that correctly shows the current Page number.

On the first page contained within the rootViewController, I have a viewController in which there are multiple textFields which have to be filled in with a pickerView. I have also created an inputAccessory toolBar which accompanies the pickers. Once all the fields are filled with text, the barButton on the toolBar toggles to Done. On the tap of this 'Done' button, within this viewController, I want the rootViewController to go to the next page.

I first tried to directly present the viewController I wanted to turn to but noticed that the page was not presented as a part of the pageViewController(it seems pretty obvious why it didn't work now!). So I then tried to implement a protocol which would trigger the rootViewController to turn to the next page. I've implemented everything perfectly but the delegate is not being set. I can't seem to fathom why it isn't being set. Could this be because of something I may have missed in the UIPageViewController framework flow? I am stumped.

Ultimately in the protocol I am trying to communicate between a contained ViewController and the rootViewController.

Here is my source code:

In the rootController:

import UIKit

class rootPageViewController: UIViewController, UIPageViewControllerDataSource,
UIPageViewControllerDelegate, tutorialPageTurnerDelegate {

var tutorialOne = userInputViewController()

@IBOutlet var pageLight: UIPageControl!

var turn: UIPageViewController!
let pages = ["userInput","tutorialOne","tutorialTwo","connectScreen"]
var i: Int!

override func viewDidLoad() {
super.viewDidLoad()

if let take = storyboard?.instantiateViewControllerWithIdentifier("pageView") {

self.addChildViewController(take)
self.view.addSubview(take.view)
take.view.addSubview(pageLight)
take.view.bringSubviewToFront(pageLight)

turn = take as! UIPageViewController
turn.dataSource = self
turn.delegate = self

// the delegate for the protocol I've implemented
tutorialOne.delegate = self

turn.setViewControllers([viewControllerAtIndex(0)!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
turn.didMoveToParentViewController(self)

}

}

.
.
... pageviewcontroller protocol functions and misc code ...
.
.

// Helper Function to return Index
func viewControllerAtIndex(index: Int) -> UIViewController? {

let vc = storyboard?.instantiateViewControllerWithIdentifier(pages[index])

// _________EDIT_________
if index == 0 {
var tutorialOne: userInputViewController = userInputViewController()
tutorialOne.delegate = self
}
return vc

}


// function required by the protocol
func saveActionCompleted() {

print("Yes it does come here")
turn.setViewControllers([viewControllerAtIndex(1)!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
turn.didMoveToParentViewController(self)

}
...


Now here is the viewcontroller where I've created the protocol:

import UIKit
import CoreData

protocol tutorialPageTurnerDelegate {
func saveActionCompleted()
}

class userInputViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate,
UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {


var delegate: tutorialPageTurnerDelegate?

override func viewDidLoad() {
super.viewDidLoad()

//Create toolbar
let toolBar = UIToolbar()
toolBar.barStyle = UIBarStyle.Default
toolBar.translucent = true
toolBar.tintColor = UIColor(red: 81/255, green: 45/255, blue: 168/255, alpha: 1)
toolBar.sizeToFit()

let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Plain, target: self, action: "donePicker")
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
toolBar.setItems([spaceButton, nextButton], animated: false)
toolBar.userInteractionEnabled = true

....... more misc code ...

}

// The selector function for the toolbar from where I want to notify the root controller
func donePicker(){

self.view.endEditing(true)
saveDataAction(self)

if delegate != nil {
delegate!.saveActionCompleted()
} else {
print("PageTurnerDelegate is nil")
}
}
...
} //End


I'm getting PageTurnerDelegate is nil. I tried a bunch of workarounds but all in vain. I do get the feeling that there may be a better way of doing this. Any suggestions or insights are most welcome!

Answer

You need to set the delegate property of the view controller instance that will be displayed:

func viewControllerAtIndex(index: Int) -> UIViewController? {

    let vc = storyboard?.instantiateViewControllerWithIdentifier(pages[index])
    if index == 0 {
            let userInputViewController =vc as! userInputViewController
            userInputViewController.delegate = self
    }
    return vc
}

Also, by convention, classes start with an upper case letter, so it should be UserInputViewController

Comments