0

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!

Jobs
  • 628
  • 7
  • 27
  • I don't see where you are setting your tutorialOne variable as the first view controller. Can you show `viewControllerAtIndex` ? – Paulw11 Jul 13 '16 at 05:35
  • I've made the edit. You can see `viewControllerAtIndex` within the rootViewController code snippet – Jobs Jul 13 '16 at 07:23
  • So, in that method you are instantiating a new view controller but you never set the delegate. So you have a view controller instance `tutorialOne` where you set the delegate, but you never show this instance, then you will have other view controller instances returned by `viewControllerAtIndex` where you never set the delegate – Paulw11 Jul 13 '16 at 07:29
  • Okay so I went into the `viewControllerAtIndex` function and tried to set the delegate for tutorialOne in there, but it wasn't still not being set. Could you elaborate a bit as to what you mean by 'you never show this instance'? – Jobs Jul 13 '16 at 07:57
  • I meant that you allocate an instance of `userInputViewController` and put it in `tutorialOne` but you never actually show `tutorialOne`. Setting the delegate in `viewControllerAtIndex` should work – Paulw11 Jul 13 '16 at 08:17
  • I tried that, but it still doesn't work. You can check the edit in the question. Its in the `viewControllerAtIndex` function. The delegate still returns nil. – Jobs Jul 13 '16 at 08:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/117179/discussion-between-paulw11-and-jobs). – Paulw11 Jul 13 '16 at 08:45

1 Answers1

2

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

Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • Sure I'll keep that in mind. Thanks a lot for the advice. The protocol is working now. – Jobs Jul 13 '16 at 09:12