简体   繁体   中英

iOS Development: How can I preload a view controller before pushing it onto the navigation stack?

I'm diving into iOS development and I'm building a puzzle game to help me become familiar with the platform. I have AdWhirl displaying ads in the score screen that is displayed when the user completes a puzzle. The problem is, it takes at least a few seconds for the score screen view controller to request and receive the ad, in which time the user looks at the score and moves onto a different view. I'm planning to implement an animation that occurs when the user solves a puzzle and the time it takes for the animation to finish would be a good time to request and receive the ad that will be displayed in the next (score) view the user will be taken too.

During the time that the solved-the-puzzle animation is taking place, how can I preload the next view controller so that the ad is present when I push the view controller on to the navigation stack? If this isn't possible, or if it's a bad idea, do you have any suggestions for how I can request and receive the ad while the animation is taking place?

Thanks so much in advance for your wisdom!

Note: For those who aren't familiar with AdWhirl, the process of requesting and receiving an ad is simple. In the viewDidLoad method of the view controller you want the ad to appear in, you create an AdWhirlView (subclass of UIView), add it as subview, and call a method that requests an ad. When the ad arrives, it calls a delegate method to display it in the parent view.

There is a side effect with just using [viewController loadView] and that is that viewDidLoad will not be called automatically after the view has loaded.

To do it properly and to make sure that viewDidLoad gets called, instead of calling loadView yourself you can instantiate the UIViewController´s view using

  UIView *view = myViewController.view;

or

  UIView *view = [myViewController view];

This will both call loadView (if the view was not already loaded) and then viewDidLoad when the view has finished loading.

In response to the accepted answer, you must not call -loadView manually. From the documentation :

You should never call this method directly. The view controller calls this method when its view property is requested but is currently nil. This method loads or creates a view and assigns it to the view property.

Instead you should just call [myViewController view] which will trigger the view to load.

As always, read the documentation!

Put this on your delegate's application:didFinishLaunchingWithOptions:

  dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
                   UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MyStoryboard" bundle:[NSBundle mainBundle]];
                   [storyboard instantiateViewControllerWithIdentifier: @"TheViewControllerYouWantToPreload"];
                 });

The dispatch_async will make the whole thing load in background.

In iOS 9 a new method was added loadViewIfNeeded() . I believe it was originally intended for unit testing of view controllers, but it should work for this case as well.

Two functions are available in iOS 5 and above.

  • setNeedsLayout()
  • layoutIfNeeded()

Calling setNeedsLayout() is like telling the system that you want to update the layout of the called views and sub-views and redraw them. Changes are not immediately reflected. As the name also includes, it simply sets the mark and reflects it in the scheduling. Changes can only be reflected in the view when the next update cycle is returned.

It is important that the task caused by the call of this method is performed asynchronously. Therefore, the developer does not know when the update cycle will come to reflect the change.

On the other hand, layoutIfNeeded() is a synchronous call. They are asking the system to reflect the changes immediately. As the name suggests, layout is done immediately. Thus, the change is already reflected in the view by the time control is returned after the call of this method has been made.

You can call the loadView manually, I don't know if there are any side effect but I don't think so.

Thanks Tommy, indeed, accessing the view property ensure that loadView will only be effectively called only if the view hierarchy is not loaded yet, avoiding any potentiial leak if the loadView code does note cope with it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM