ここでの回答はすべて参考になりますが、問題を処理する別の方法があります。
UIPageViewController は、スクロール遷移スタイルで間違ったページに移動します
この問題への回答を最初に検索したとき、検索の言い回しが、リンクしたばかりの質問ではなく、この質問に巻き込まれたため、この別の質問にリンクする回答を投稿する義務があると感じました。見つけたので、少し詳しく説明します。
この問題は、ここのマットによってかなりよく説明されています。
これは実際には UIPageViewController のバグです。スクロール スタイル (UIPageViewControllerTransitionStyleScroll) でのみ発生し、animated:YES で setViewControllers:direction:animated:completion: を呼び出した後にのみ発生します。したがって、次の 2 つの回避策があります。
UIPageViewControllerTransitionStyleScroll を使用しないでください。
または、setViewControllers:direction:animated:completion: を呼び出す場合は、animated:NO のみを使用してください。
バグを明確に確認するには、setViewControllers:direction:animated:completion: を呼び出してから、(ユーザーとして) インターフェースで、手動で前のページに左 (戻る) に移動します。間違ったページに戻ります。前のページではなく、setViewControllers:direction:animated:completion: が呼び出されたときにいたページです。
バグの理由は、スクロール スタイルを使用する場合、UIPageViewController が何らかの内部キャッシュを行うためと思われます。したがって、setViewControllers:direction:animated:completion: の呼び出し後、内部キャッシュのクリアに失敗します。前のページが何であるかを知っていると思います。したがって、ユーザーが前のページに左方向に移動すると、UIPageViewController は dataSource メソッド pageViewController:viewControllerBeforeViewController: の呼び出しに失敗するか、間違った現在のビュー コントローラーで呼び出します。
これは適切な説明であり、この質問で指摘されている問題とはまったく異なりますが、非常に近いものです。setViewControllers
ユーザーが次にジェスチャでパンしたときに、UIPageViewController がそのデータ ソースを強制的に再クエリするかどうかについての行に注意してくださいanimated:NO
。これは、「どこにあるか」または現在のビュー コントローラーの隣にあるビュー コントローラーがわからなくなるためです。 .
ただし、アニメーションで PageView をプログラムで移動する必要がある場合があったため、これはうまくいきませんでした。
したがって、最初に考えたのはsetViewControllers
、アニメーションを使用して呼び出し、完了ブロックで、現在表示されているビュー コントローラーを使用してメソッドを再度呼び出すことでしたが、アニメーションは使用しませんでした。したがって、ユーザーは問題なくパンできますが、メソッドを再度呼び出して、ページ ビューをリセットします。
残念ながら、試してみると、ページビューコントローラーから奇妙な「アサーションエラー」が発生し始めました。それらは次のようになります。
*** -[UIPageViewController queuingScrollView: ... でのアサーションの失敗
なぜこれが起こったのか正確にはわからなかったので、私は後戻りし、最終的にJai の答えを解決策として使用し始め、まったく新しい UIPageViewController を作成し、それを UINavigationController にプッシュしてから、古いものを取り出しました。ひどいですが、ほとんどの場合は機能します。次のように、UIPageViewController から時折アサーション エラーが発生することがあります。
*** -[UIPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:] でのアサーションの失敗、/SourceCache/UIKit_Sim/UIKit-2380.17/UIPageViewController.m:1820 $1 = 154507824 可視ビューを管理するビュー コントローラーがありません >
そしてアプリが落ちる。なんで?さて、検索すると、上で言及したこの他の質問が見つかりました。特に、単純に呼び出して、同じビューコントローラーで呼び出しが完了したらすぐにUIPageViewControllerをリセットするという私の最初のアイデアを支持する受け入れられた答えが見つかりましたが、それは持っていました欠落している要素: そのコードをメイン キューに呼び戻します! コードは次のとおりです。setViewControllers: animated:YES
setViewControllers: animated:NO
__weak YourSelfClass *blocksafeSelf = self;
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL finished){
if(finished)
{
dispatch_async(dispatch_get_main_queue(), ^{
[blocksafeSelf.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];// bug fix for uipageview controller
});
}
}];
わお!これが実際に私にとって理にかなっている唯一の理由は、WWDC 2012 セッション 211、Building Concurrent User Interfaces on iOS (開発者アカウントでここから入手可能) を見たからです。UIKit オブジェクト (UIPageViewController など) が依存するデータ ソース オブジェクトを変更しようとして、それをセカンダリ キューで実行すると、厄介なクラッシュが発生する可能性があることを思い出しました。
特に文書化されているのを見たことがありませんが、実際にそうであると想定して読み進めなければならないのは、アニメーションの完了ブロックがメイン キューではなくセカンダリ キューで実行されるということです。setViewControllers animated:NO
UIPageViewController が最初に完了ブロックを呼び出そうとしたときとsetViewControllers animated:YES
、単に UINavigationController を使用して新しい UIPageViewController をプッシュしようとしたときの両方で、UIPageViewController がしゃがんでアサーションに失敗した理由)のブロックは、setViewControllers animated:YES
すべてそのセカンダリ キューで発生しているためです。
アニメーション完了ブロックから来て、それをメイン キューに送り返すため、UIKit でストリームを横断しないため、そこにあるコードの一部が完全に機能するのはそのためです。素晴らしい。
とにかく、誰かがこの問題に出くわした場合に備えて、この旅を共有したかった.
編集:誰かが興味を持っている場合は、こちらの Swift バージョン。