testinggnitset ser
testinggnitset ser

Reputation: 297

UIPageViewController initial swipe called twice

The below function is how I display different views when a user swipes right where self.viewControllerAtIndex() is my own custom function that returns a view. The problem is that the first swipe outputs "---------swipe Right before 0" twice. And then works perfectly like expected afterwards.

func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
    print("---------swipe Right before " + String(index))
    index += 1
    print("---------swipe Right " + String(index))

    if index == (products!.count) {
        index = 0
    }

    return self.viewControllerAtIndex(index:index)

}
=====CONSOLE OUTPUT=====
---------swipe Right before 0
---------swipe Right 1
---------swipe Right before 0
---------swipe Right 1

 func viewControllerAtIndex(index: Int) -> ViewController{

   return ViewController.init(id: index)
 }

For some reason, every other swipe after the first works as expected. The initial swipe is what causes the console output above. This causes my view sequence to look like below (2 views)

First Swipe
View1
Second Swipe
View1
Third Swipe
View2
Fourth Swipe
View1
Fifth Swipe
View2

I'm also initiating my uiPageViewController like so

let array = [ViewController](repeating: ViewController.init(videos: (self.videos![self.products![self.index].id]!)), count: 1)

self.UIViewPageController?.setViewControllers(array, direction: UIPageViewControllerNavigationDirection.forward, animated: false, completion: nil)

So I'm creating a new ViewController on viewDidLoad and then when a user swipes, I'm creating new ViewControllers

Upvotes: 0

Views: 1578

Answers (2)

Lennart Wisbar
Lennart Wisbar

Reputation: 332

Too long for a comment ... Chris Trahey's is the correct answer.

I had the same problem, based on the misunderstanding that the viewControllerBefore/viewControllerAfter methods meant "What should happen if the user swipes right/left". Like you said, these methods only answer the question: "Which view controller comes before/after a given view controller?" They should only answer that question, without any side effects.

A solution for some scenarios would be to add an index property to the view controller class, and set that index on creation. That's useful if you're not working directly with an array of view controllers, but create them on the fly. Then, instead of saying array.index(of: vc), you can say vc.index. See here: https://stackoverflow.com/questions/25795093/swift-uipageviewcontroller-always-repeats-second-viewcontroller#=

EDIT: Oh, and if you want to actually react to a page turn, you can do that in pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:).

Upvotes: 0

Chris Trahey
Chris Trahey

Reputation: 18290

I think you should avoid doing index state management in this method. Apple does not guarantee the circumstances under which this method is called. If I had to paraphrase, I would say that while the framework is asking you for the view controller that should come after the provided one, you are answering a different question: Which view controller comes after the one you previously told us about?

To get around this, you need to use your original array of view controllers, find the index of the passed-in view controller in that array, and return the view controller that comes next (or nil if you are at the end of the array).

Upvotes: 2

Related Questions