Rowan Freeman Rowan Freeman - 1 month ago 11
Swift Question

Why isn't my PageViewController's DataSource working correctly?

I have created a simple storyboard with a PageView Controller.

I will flip between two other View Controllers.

My PageView Controller is a custom class

TutorialPageViewController
. I've also created a custom DataSource class.

In the DataSource class I expect the
pageViewController
methods to be called when I attempt to scroll. However this is not the case. I have break points at both methods and they are never called.

The first view controller, "Page the first" comes up correctly, but attempting to scroll around doesn't call the methods, so I can't use them yet (hence they return nil for now).

If I set the DataSource of my view controller to
self
and put the methods in there, they are called correctly. But I want to move the methods out to a separate class for better code management. So why doesn't it work?

I've tried


  • Setting my DataSource class to be a
    UIScrollViewDelegate
    as well as a
    UIPageViewControllerDelegate
    and setting the view controller's
    delegate
    to be the DataSource

  • The PageView's transition style is Scroll



Storyboard overview

class TutorialPageViewController : UIPageViewController {
override func viewDidLoad() {
reset()
}

func reset() {
let dataSource = TutorialPageDataSource(storyBoard: storyboard!)
let content = dataSource.firstContentViewController

self.dataSource = dataSource

self.setViewControllers([content], direction: .forward, animated: true, completion: nil)
}
}

class TutorialPageDataSource : NSObject, UIPageViewControllerDataSource {
private var _storyboard: UIStoryboard

var firstContentViewController: UIViewController
var secondContentViewController: UIViewController

init(storyBoard: UIStoryboard) {
_storyboard = storyBoard
firstContentViewController = _storyboard.instantiateViewController(withIdentifier: "FirstContentViewController")
secondContentViewController = _storyboard.instantiateViewController(withIdentifier: "FirstContentViewController")
}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
// break point here never reached
return nil
}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
// break point here never reached
return nil
}
}

Answer

UIPageViewController dataSource (and delegate) are weak.

You create your TutorialPageDataSource instance in the reset method, assign it to the weak dataSource, and then the TutorialPageDataSource instance goes out of scope and gets deallocated because there is no strong reference to it any more. So now the page view controller's dataSource becomes nil.

You need to keep a strong reference to the TutorialPageDataSource instance. Use an instance variable to keep the reference.

Comments