I essentially have a a root ViewController that I want passed onto the collection of ViewControllers (all different classes themselves) connected through the PageViewController.

Currently, I set up a prepareforsegue in the root ViewController passing data. I then declared the variable in the PageViewController and trying to figure how to pass the data onto the ViewControllers.

I'm currently just doing a simple Hello World test, so my code is a bit simple. Here is my RootViewController which I have passing onto the PageViewController (and hence onto the subsequent VC's connected to the PageViewController):

class RootViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    var hello: String! = "Hello World!"
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if (segue.identifier == "testSegue"){

            var svc = segue.destinationViewController as! PageViewController;

            svc.datapassed = self.hello

        }
    }

My PageView Controller is a bit more complicated. I'm using the storyboard ID method, since I want the pageviewcontroller to display view controllers of different classes as opposed to the multitude of tutorials which show one view controller template and different image contents...

    class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

        var datapassed: String!

        var index = 0
        var identifiers: NSArray = ["FirstNavigationController", "SecondNavigationController"]

        override func viewDidLoad() {
            super.viewDidLoad()
            setupPageControl()
            self.dataSource = self
            self.delegate = self

            let startingViewController = self.viewControllerAtIndex(self.index)
            let viewControllers: NSArray = [startingViewController]
            self.setViewControllers(viewControllers as [AnyObject], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)

            // Do any additional setup after loading the view.
        }

        func viewControllerAtIndex(index: Int) -> UIViewController! {
            if index == 0 {

                return self.storyboard!.instantiateViewControllerWithIdentifier("FirstNavigationController") as! UIViewController

            }
            if index == 1 {

                return self.storyboard!.instantiateViewControllerWithIdentifier("SecondNavigationController") as! UIViewController
            }

            return nil
        }

        func pageViewController(pageViewController: UIPageViewController!, viewControllerAfterViewController viewController: UIViewController!) -> UIViewController! {

            let identifier = viewController.restorationIdentifier
            let index = self.identifiers.indexOfObject(identifier!)
            if index == identifiers.count - 1 {

                return nil
            }

            self.index = self.index + 1
            return self.viewControllerAtIndex(self.index)

        }

        func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! {

            let identifier = viewController.restorationIdentifier
            let index = self.identifiers.indexOfObject(identifier!)
            if index == 0 {

                return nil
            }
            self.index = self.index - 1
            return self.viewControllerAtIndex(self.index)

        }

        private func setupPageControl() {
            let appearance = UIPageControl.appearance()
            appearance.pageIndicatorTintColor = UIColor.grayColor()
            appearance.currentPageIndicatorTintColor = UIColor.whiteColor()

        }

        func presentationCountForPageViewController(pageViewController: UIPageViewController!) -> Int {
            return self.identifiers.count
        }

        func presentationIndexForPageViewController(pageViewController: UIPageViewController!) -> Int {
            return 0
        }

    }

Lastly, I simply want the first ViewController connected to the pageviewcontroller to display the text from the variable passed, datapassed.

    class FirstViewController: UIViewController {

        @IBOutlet weak var helloLabel: UILabel!
        override func viewDidLoad() {
            super.viewDidLoad()
            helloLabel.text = datapassed
            // Do any additional setup after loading the view.
        }
    }

EDIT: Possible Solution and Final Code:

    class RootViewController: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()

        }

        var carinfos: String! = "Hello World"
        override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
            if let svc = segue.destinationViewController as? PageViewController
                where segue.identifier == "testSegue" {
                    svc.dataPassed = self.carinfos
            }
        }
    }

class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var dataPassed: String? {
        didSet {
            self.updateCurrentViewController()
        }
    }

    var index = 0
    var identifiers: NSArray = ["FirstNavigationController", "SecondNavigationController"]


    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = self
        self.delegate = self

        let startingViewController = self.viewControllerAtIndex(self.index)
        let viewControllers: NSArray = [startingViewController]
        self.setViewControllers(viewControllers as [AnyObject], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)

    }

    func updateCurrentViewController() {

        if let firstViewController = self.viewControllerAtIndex(self.index) as? FirstViewController, let data = self.dataPassed {
            firstViewController.dataPassed = data
        }
    }


    func pageViewController(pageViewController: UIPageViewController!, viewControllerAfterViewController viewController: UIViewController!) -> UIViewController! {

        let identifier = viewController.restorationIdentifier
        let index = self.identifiers.indexOfObject(identifier!)
        if index == identifiers.count - 1 {

            return nil
        }
        self.index = self.index + 1
        return self.viewControllerAtIndex(self.index)

    }

    func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! {

        let identifier = viewController.restorationIdentifier
        let index = self.identifiers.indexOfObject(identifier!)

        if index == 0 {

            return nil
        }

        self.index = self.index - 1
        let viewController = self.viewControllerAtIndex(self.index)
        self.updateCurrentViewController()

        return viewController
    }


    func viewControllerAtIndex(index: Int) -> UIViewController! {
        if index == 0 {
            return self.storyboard!.instantiateViewControllerWithIdentifier("FirstNavigationController") as! UIViewController
        }
        if index == 1 {
            return self.storyboard!.instantiateViewControllerWithIdentifier("SecondNavigationController") as! UIViewController
        }
        return nil
    }

    func presentationCountForPageViewController(pageViewController: UIPageViewController!) -> Int {
        return self.identifiers.count
    }

    func presentationIndexForPageViewController(pageViewController: UIPageViewController!) -> Int {
        return 0
    }


}

class FirstViewController: UIViewController {
    var dataPassed: String?

    @IBOutlet weak var firstLabelTest: UILabel!
    @IBOutlet weak var firstLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        println(dataPassed)
        firstLabel.text = "Hello, this is First"
        self.populateData()
    }

    func populateData() {
        if let data = self.dataPassed {
            self.firstLabelTest.text = self.dataPassed
        }
    }

}
3

There are 3 answers

3
Patrick Lynch On

You can simply pass it through the view controller structure to get this working, although that's not much of a thoughtful design. To do that, first, make sure you are properly casting the destinationViewController using an if let binding and a conditional downcast (as?). You can also combine the comparison to the segue's identifier using a where clause. Then, you'll have the object on which to set your data.

In FirstViewController, use a property observer to update the label when your dataPassed variable it set, and also update it on viewDidLoad.

Also, your hello property should not be an implicitly unwrapped type, so you can remove the ! from the declaration.

class FirstViewController : UIViewController {

    @IBOutlet weak var helloLabel: UILabel!

    var dataPassed: String?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.populateData()
    }

    func populateData() {
        if let data = self.dataPassed {
            self.helloLabel.text = self.dataPassed
        }
    }

}

class PageViewController : UIPageViewController {

    var index = 0
    var identifiers: NSArray = ["FirstNavigationController", "SecondNavigationController"]

    var dataPassed: String? {
        didSet {
            self.updateCurrentViewController()
        }
    }

    func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! {

        let identifier = viewController.restorationIdentifier
        let index = self.identifiers.indexOfObject(identifier!)
        if index == 0 {

            return nil
        }
        self.index = self.index - 1
        let viewController = self.viewControllerAtIndex(self.index)

        self.updateCurrentViewController()

        return viewController
    }

    func updateCurrentViewController() {

        if let firstViewController = self.viewControllerAtIndex(self.index) as? FirstViewController, let data = self.dataPassed {
            firstViewController.dataPassed = data
        }
    }

    func viewControllerAtIndex(index: Int) -> UIViewController! {
        // Create your VC as in the project template
        return nil
    }
}

class RootViewController : UIViewController {

    var hello: String = "Hello World!"

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        super.prepareForSegue( segue, sender: sender )
        if let svc = segue.destinationViewController as? PageViewController
            where segue.identifier == "testSegue" {
                svc.dataPassed = self.hello
        }
    }
}
0
Patrick Lynch On

Depending on the needs and other structure of your app, you could also use the responder chain to provide data to any view controllers in your hierarchy.

Then it's a simple as this:

class FirstViewController : UIViewController {

    @IBOutlet weak var helloLabel: UILabel!

    var dataPassed: String? {
        didSet {
            if let data = self.dataPassed {
                self.helloLabel.text = data
            }
        }
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        if let dataSource = self.nextResponder()?.targetForAction( "hello", withSender: self ) as? RootViewController {
            self.dataPassed = dataSource.hello
        }
    }

}

class RootViewController : UIViewController {

    var hello: String = "Hello World!"

}
0
Mahesh Giri On

In swift3 you can do like In Main view where you embeded an pageviewcontroller you can use segue with identifier

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier=="challengepostssegue"{
         let destination=segue.destination as! PageMainController
            destination.challengeId=challengId
        }
    }

In PageMainController declare one variable optional type

var challengeId:String?