Preloading pages of UIPageViewController
Asked Answered
B

1

13

I can't find a good solution to having the UIPageViewController preload the surrounding ViewControllers.

Right now what happens is when the user starts to turn the page, nothing happens, the code calls

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
       viewControllerAfterViewController:(UIViewController *)viewController

and once its loaded thennnn it shows the animation. This takes too long and is not smooth.

Anyone have a solution?

Battista answered 25/7, 2012 at 22:26 Comment(0)
A
19

Create a mutable container and when you show the first view, create the two viewController that would be needed if the user pages, once you have the viewController object ask it for its view (to get it to load the nib and call the controller's "viewDidLoad:" method. You need to figure out a system on identifying the viewControlers so you can retrieve the viewController you need). You might be able to do the heavy lifting here in a block on a dispatch_queue.

From then on, when the user pages, you look first in the container for the viewController, and if not found, you have to do it in real time.

You probably want to use a dispatch_group so that you can wait on it for pending blocks to finish before paging.

Everytime the user pages, you will look and see if the pages surrounding that page are in the container or not. You could also pre-fetch more viewControllers - like two forward two reverse at each page shown.

Altogether answered 25/7, 2012 at 22:47 Comment(14)
I basically have this implemented, and I have the call to ask for the controllers view (to call viewdidload), but it still has a significant delay from when the user starts to scroll and from when it displays the controller. Its as if its not really loaded, just partiallyBattista
So, do you have all your "heavy lifting" done in viewDidLoad, or do you have some in viewWillAppear? I am using this technique with great success...Altogether
The only thing my content view controller does is in viewdidload it sets the UIImageView (which is full screen) to an image. It doesnt do any "heavy lifting" anywhere.Battista
So you then have some problem you don't know about. If the "new" viewController only does some minimal amount of work. why the delay? I use this feature with no problems, yet my viewControllers have a lot of compelexity, must load many images and complex text items. Something is amiss here.Altogether
My workflow is as follows. The app starts with one photo displayed. The user then presses a button to open the camera, this image is returned to controller, I create and initialize a new contentviewcontroller with this image, I then add this controller to a mutablearray. Now in pageViewController:viewControllerAfterViewController: I simply find and return the correct content controller (the one just created for example). Every flip after it loads once is fine, its just that initial time...Battista
@DavidH Any chance you have some sample code on how you do this? Have somewhat complicated View controllers, and would love to be able to scroll through them at a very high pace (or rather, for my users to do that), but can't quite get it optimized to my liking. Curious how you are using dispatch_group.Cologne
@BobSpryn Dispatch group provides a way to wait until all group blocks complete. You now mentioned the camera, and there are system delays with it you can do nothing about. My point on the vcs is that you can often do with UI elements what you do with strings etc - that is put them in mutable containers for future use.Altogether
Camera? I don't think I mentioned that here. No I'm not showing the camera in this instance. Rather I'm asking if you are somehow rendering view controllers in a background thread somehow, and curious what that looks like.Cologne
I am having this exact problem, and my issues is that the content of my view controllers is a UICollectionView, and I fail to cache the cells here. When I initially swipe to the next view controller cellForItemAtIndexPath: is called and creates a lag. Any suggestions for solving this?Falcate
@Falcate create a method to tell those classes to create and cache the cells, and another to finally release them. Perhaps you can get that to work. If not the cells then the content they eventually need ie images, attributed text, and put those in an NSCache.Altogether
@DavidH This is a very elegant solution, but can you provide a little more guidance regarding the use of a dispatch_queue please? Won't this be UI work on a background thread?Adjourn
@BenPackard what most people don't understand is that if UI is showing - it has a window property - all changes must be done on the main thread. However, if you are just constructing or loading a UI element, and its not showing, its usually safe to load it from a nib or otherwise populate it. You can create a new serial queue and associate it with the background thread, and once the view is setup post a block to the main thread with the newly created and configured view. You can find a huge amount of info on GCD, dispatch queues, etc on the Apple site and here.Altogether
@DavidH In a for loop of my 3 views, I scroll to the first and print(someViewController.view) to pre-load the other 2. Doesn't feel right, but works a charm.Finicky
@Finicky try just putting "someViewController.view" on a line by itself.Altogether

© 2022 - 2024 — McMap. All rights reserved.