pageViewController(_: viewControllerBefore:) および pageViewController(_: viewControllerAfter:) が呼び出されるタイミングについて(UIPageViewController)

## 前提

- Swift 3
- 表示するViewControllerは常時１枚だけ

## 経緯

- publicなプロパティにセットされた数字を表示するだけのViewControllerがある
- UIPageViewControllerを使い、端の制限がないページングを行いたかった
    - スワイプすることで上記ViewControllerの数字をカウントアップ、カウントダウンさせたかった

# tl;dr

- PageViewControllreは表示中のViewControllerの前後になるべくViewControllerを生成して待機させている
- 初期化してから初めてのページング開始時に`pageViewController(_: viewControllerBefore:)`および`pageViewController(_: viewControllerAfter:)`が一度ずつ呼ばれる
- ページング完了時に、ページング方向応じて`pageViewController(_: viewControllerBefore:)`および`pageViewController(_: viewControllerAfter:)`が一度呼ばれる
- 引数のviewControllerを元に相対で適切な値を決定してあげましょう

## 期待したとおりに動かないコード

```swift
class ViewController: UIViewController {
    public var number: Int = 0
    @IBOutlet weak var simpleLabel: UILabel!

    override func viewWillAppear(_ animated: Bool) {
        simpleLabel.text = number.description
    }
}
class PageViewController: UIPageViewController, UIPageViewControllerDataSource {
    var number: Int = 0
    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = self

        // 初期表示するViewControllerをセットする
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        vc.number = self.number
        self.setViewControllers([vc], direction: .forward, animated: true)
    }
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        // 後方のViewControllerを生成するため、カウントダウンしたい
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        self.number -=1
        vc.number = self.number
        return vc
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        // 前方のViewControllerを生成するため、カウントアップしたい
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        self.number +=1
        vc.number = self.number
        return vc
    }

}
```

## 期待したとおりに動くコード
```swift
class ViewController: UIViewController {
    public var number: Int = 0
    @IBOutlet weak var simpleLabel: UILabel!

    override func viewWillAppear(_ animated: Bool) {
        simpleLabel.text = number.description
    }
}
class PageViewController: UIPageViewController, UIPageViewControllerDataSource {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = self

        // 初期表示するViewControllerをセットする
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        vc.number = 0
        self.setViewControllers([vc], direction: .forward, animated: true)
    }
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        // 後方のViewControllerを生成するため、カウントダウンしたい
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        vc.number = (viewController as! ViewController).number - 1
        return vc
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        // 前方のViewControllerを生成するため、カウントアップしたい
        let vc:ViewController = // コード生成したりStoryboardから取ったり
        vc.number = (viewController as! ViewController).number + 1
        return vc
    }

}
```

# 該当メソッドが呼び出されるタイミングについて整理

## PageViewController初期化からページング完了までを図解

![pagevc-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/42032/21675c4c-d4e2-e44c-e9ae-afc6177990c2.jpeg)
これは`PageViewController.viewDidLoad()`が完了した直後のイメージ図です。
薄緑色は上記の`ViewController`、外側の枠は`PageViewController`です。

![pagevc-1 (1).jpg](https://qiita-image-store.s3.amazonaws.com/0/42032/7300c7f3-1ba1-d7cc-02eb-e967c1e384ef.jpeg)
After方向のスワイプイベントが発生しました。

![pagevc-1 (2).jpg](https://qiita-image-store.s3.amazonaws.com/0/42032/99bb035c-1b4e-ade6-5d69-58bc44de6224.jpeg)
ページングを開始しますが、表示するViewControllerが存在しないため、`pageViewController(_: viewControllerAfter:)`を呼び出し、先のViewControllerを生成します。

![pagevc-1 (3).jpg](https://qiita-image-store.s3.amazonaws.com/0/42032/9cc1bd5f-89fd-6386-e861-1c2455560eed.jpeg)
また、Before方向のViewControllerも存在していないために`pageViewController(_: viewControllerBefore:)`も呼び出し、後方のViewControllerも生成します。

![pagevc-1 (4).jpg](https://qiita-image-store.s3.amazonaws.com/0/42032/528c9d57-0d9e-54dc-5fca-90399ba489e5.jpeg)
ページング中……

![pagevc-1 (5).jpg](https://qiita-image-store.s3.amazonaws.com/0/42032/73d78115-38ab-5863-ab94-6ab795b5e021.jpeg)
ページングが完了しました。次のページング処理に備え、`pageViewController(_: viewControllerAfter:)`を呼び出し、先のViewControllerを生成します。

## 問題のコードでは何が起きていたか

![pagevc-1 (6).jpg](https://qiita-image-store.s3.amazonaws.com/0/42032/3868b8ee-d613-5d96-9425-7c73dbd11044.jpeg)
問題のコードをより反映した図になります。丸い要素は`PageViewController.number`を表したものです。

![pagevc-1 (7).jpg](https://qiita-image-store.s3.amazonaws.com/0/42032/06aad01c-bef1-0064-2ef9-23540afc9757.jpeg)
After方向のスワイプイベントが発生して先のViewControllerが生成されました。
`pageViewController(_: viewControllerAfter:)`によって`PageViewController.number`がカウントアップされます。

![pagevc-1 (8).jpg](https://qiita-image-store.s3.amazonaws.com/0/42032/eca54de3-06ad-3463-3c58-33d0ad889961.jpeg)
また、後方のViewControllerも生成されました。
`pageViewController(_: viewControllerBefore:)`によって`PageViewController.number`がカウントダウンされます。

![pagevc-1 (9).jpg](https://qiita-image-store.s3.amazonaws.com/0/42032/0720a2e7-a40a-0cb3-e00b-9334a0a70c20.jpeg)
ページング中……

![pagevc-1 (10).jpg](https://qiita-image-store.s3.amazonaws.com/0/42032/6caa5884-1607-d623-6004-16e64853c62e.jpeg)
ページングが完了しました。次のページング処理に備え、先のViewControllerを生成します。
`pageViewController(_: viewControllerAfter:)`によって`PageViewController.number`がカウントアップされます。

# まとめ
- `pageViewController(_: viewControllerBefore:)`および`pageViewController(_: viewControllerAfter:)`では、生成されようとしているViewControllerの前後のViewControllerが取得できる
- なので、前後のViewControllerに対してどういう値が適切なのかを考えるようにする