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.