Search code examples
iosswiftxcodedelegatesuipageviewcontroller

Swift: Call Function in PageViewController from other Viewcontroller


I got an PageViewController which loads two "child "ViewControllers in order to let the user "swipe" through them. I don't want this swipe gesture , but instead I want to have a function inside my ViewController which allows me to use setViewControllers in the PageViewController.

I tried using protocols but even that didn't work out.

I would realy appreciate any help or suggestions on how I could accomplish that. Thanks!


Solution

  • To access setViewControllers from your child view controllers, you will need your child view controllers to be aware of their parent PageViewController. To do so, start by making a Protocol (I know you've said you've tried Protocols, but please please see my method through). This Protocol will ensure that every child view controller has a reference to the parent PageViewController.

        protocol PageObservation: class {
            func getParentPageViewController(parentRef: PageViewController)
        }
    

    Ensure that your child view controllers adhere to the PageObservation Protocol.

        class Child1ViewController: UIViewController, PageObservation {
            var parentPageViewController: PageViewController!
            func getParentPageViewController(parentRef: PageViewController) {
                parentPageViewController = parentRef
            }
        }
    
        class Child2ViewController: UIViewController, PageObservation {
            var parentPageViewController: PageViewController!
            func getParentPageViewController(parentRef: PageViewController) {
                parentPageViewController = parentRef
            }
        }
    

    In your PageViewController, as you create each child view controller, cast them to the PageObservation type and pass a reference of the parent PageViewController. I use an array called orderViewControllers to create my pages. My UIPageViewControllerDataSource delegate methods uses it to know which pages to load but that is irrelevant to this example, I just thought I'd let you know in case you have a different way of creating your pages.

        class PageViewController: UIPageViewController {
            var orderedViewControllers: [UIViewController] = []
    
    
            //creating child 1
            //i am using storyboard to create the child view controllers, I have given them the identifiers Child1ViewController and Child2ViewController respectively
            let child1ViewController =  UIStoryboard(name: "Main", bundle: nil) .
            instantiateViewController(withIdentifier: "Child1ViewController")
            let child1WithParent = child1ViewController as! PageObservation
            child1WithParent.getParentPageViewController(parentRef: self)
    
            orderedViewControllers.append(child1ViewController)
    
            //creating child 2
            let child2ViewController =  UIStoryboard(name: "Main", bundle: nil) .
            instantiateViewController(withIdentifier: "Child2ViewController")
            let child2WithParent = child2ViewController as! PageObservation
            child2WithParent.getParentPageViewController(parentRef: self)
    
            orderedViewControllers.append(child2ViewController)
        }
    

    Now inside your child view controllers, you have access to setViewControllers. For example, if I want to call setViewControllers in the child1ViewController, I have created a func called accessSetViewControllers() where I access the setViewControllers:

        class Child1ViewController: UIViewController, PageObservation {
             var parentPageViewController: PageViewController!
            func getParentPageViewController(parentRef: PageViewController) {
                parentPageViewController = parentRef
            }
    
            func accessSetViewControllers() {
                 parentPageViewController.setViewControllers( //do what you need )
            }
        }
    

    On a side note, despite what other answers above have said, you can set dataSource to whatever you like. I sometimes set dataSource to nil to prevent the user from swiping away from a screen before doing something and then add the dataSource back to allow them to continue swiping.