Help us understand the problem. What is going on with this article?

UIPageViewControllerでページ遷移時に処理したいことを書くときのTip

More than 1 year has passed since last update.

たまに解説サイトにあるアンチパターン

ページを変わったときにする処理をUIPageViewControllerDataSourcepageViewController関数中に書く解説サイトをいくつか見ます。

extension PageViewController : UIPageViewControllerDataSource {

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        ... 
        callWhenPageChanged() // ページが変わったら呼びたい処理

        ... /*何かしらのViewControllerをreturnする処理*/
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        ...
        callWhenPageChanged() // ページが変わったら呼びたい処理

        ... /*何かしらのViewControllerをreturnする処理*/
    }
}

callWhenPageChanged()は、例えば、UIPageControl(インジケータ)の現在ページの操作を変更するための処理などが考えられますね。その場合、遷移先になりうるViewControllerの情報が必要になるのも理解できます。

確かにここのpageViewControllerは、左右にフリックしたときなどに、ページデータを提供するために呼ばれるのは確かです。
しかし、あくまでページリソースを扱う前提の関数に、そのような処理を書くのは本質的ではないと私は思います。
というか、本質的でないというか、この実装は間違えています。 この2つの関数は現在のページの前後のページにあたるViewControllerを返す関数です。ページが変わるごとに毎回呼ばれるので、毎ページでcallWhenPageChangedが2回呼ばれますね。

で、何を使えばいいの?

実は、すでにUIPageViewControllerDelegateという素晴らしいDelegateが存在します。
リファレンスにもある通り、UIPageViewControllerDelegateは、以下2つの実装をサポートしています。

// ジェスチャーによる遷移が始まる場合に呼ばれる
// willTransitionTo.firstを見れば、次の遷移先のページのインスタンスを見ることができる
func pageViewController(UIPageViewController, willTransitionTo: [UIViewController])

// ジェスチャーによる遷移が終わった場合に呼ばれる
func pageViewController(UIPageViewController, didFinishAnimating: Bool, 
                        previousViewControllers: [UIViewController], 
                        transitionCompleted: Bool)

これらは、ジェスチャーによる画面遷移イベントが発生した呼ばれる関数です。こちらのどちらかに書くほうが適してますね。

現在のページ(ViewController)を取得したい

具体的に、callWhenPageChangedを使いたいときの例を書いてみます。

extension PageViewController: UIPageViewControllerDelegate { 
        // ジェスチャーによる遷移が終わった場合に呼ばれる
        func pageViewController(_ viewController: UIPageViewController, didFinishAnimating: Bool, 
                                previousViewControllers: [UIViewController], 
                                transitionCompleted: Bool) {
                ...
                callWhenPageChanged() // ページが変わったら呼びたい処理

                ...
        }
}

では、現在表示されているページ(ViewController)を取得を取得したい場合はどうすればいよいでしょうか?
上記の関数(didFinishAnimatingがある方)では、第1引数のviewController.viewControllers.firstが現在表示されているページに当たりますので、それを見てもらえばよいです。

最後に

UIPageViewControllerDelegateの使い方をちょっとだけ解説しました。間違っていることがあればご報告お願いします。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away