17

I have not found relevant and up to date answers in the posts related to this question.

I would like to load all viewcontrollers on launch. Currently it launches as expected but when I tap on a bar item (the first time) there is a slight delay to load it because it has not been loaded yet.

How can I do that is Swift ?

Thanks.

Dan Beaulieu
  • 19,406
  • 19
  • 101
  • 135
Sam
  • 1,101
  • 2
  • 13
  • 26

5 Answers5

33

To preload a UIViewController's view, simply access its view property:

let _ = myViewController.view

To preload all view controllers on a UITabBarController, you can do:

if let viewControllers = tabBarController.viewControllers {
    for viewController in viewControllers {
        let _ = viewController.view
    }
}

Or a bit more compactly:

tabBarController.viewControllers?.forEach { let _ = $0.view }
Borzh
  • 5,069
  • 2
  • 48
  • 64
Robert
  • 5,735
  • 3
  • 40
  • 53
  • Thanks Robert, unfortunately I've already tried that solution and swift gives an error for viewController.view : 'Expression resolves to an unused l-value' – Sam Oct 21 '15 at 14:32
  • Hmm, I didn't get that error. You could try doing something like: `let _ = viewController.view` – Robert Oct 21 '15 at 14:33
  • Yes, that should work; I do get that error when used outside a playground. I'll update the answer... – Robert Oct 21 '15 at 14:36
  • When I try `let _ = viewController.view`I don't get the error but it does not seem to work when I set a breakpoint in the viewdidload methods of the ViewControllers they are not called until I actually tap the bar item. I tried your recommendation on the viewDidLoad method of the TabBarController is that correct ? – Sam Oct 21 '15 at 14:40
  • Yes, doing it on the `UITabBarController`'s `viewDidLoad` method should work. You can also verify that the views are loaded by doing: `print(viewController.isViewLoaded())` after accessing their `view` property. You should see one 'true' in the console for each tab bar item... – Robert Oct 21 '15 at 14:44
  • It prints true but does not stop on breakpoint in the viewDidLoad method of the viewcontrollers. I don't understand why I get that delay when I tap the bar items for the first time. Why I would still have that delay if the view are already loaded ? This happens only first time I tap then I can tap any bar item and see instantly the corresponding view. Thanks a lot Robert. – Sam Oct 21 '15 at 14:55
  • In fact sorry for the lack of precision on my side, what has to be loaded are navigationControllers, do you think that the views should be loaded differently then ? – Sam Oct 21 '15 at 15:00
  • I don't think it'd make any difference with navigation controllers; if you load a `UINavigationController`'s view, it should also load its `rootViewController`'s view too. You *might* want to consider adding more details to your question about the overall view controller hierarchy, and what views you have which are causing the delay. Unfortunately there's quite a lot of possibilities and it's hard to know the cause without more info! – Robert Oct 21 '15 at 15:05
  • I accepted the answer as it answers the question. Thanks Robert. – Sam Oct 21 '15 at 15:16
  • should this be done in didFinishLaunchingWithOptions? – Dan Beaulieu Feb 19 '16 at 18:51
  • 1
    @DanBeaulieu Yes; if you're using a storyboard, then the tab bar controller should be accessible via `(window?.rootViewController as? UITabBarController)` (or something similar). – Robert Feb 19 '16 at 20:34
  • Beautiful. Thanks! – PhillipJacobs Jul 03 '21 at 12:12
9

Combining Robert's and M. Daigle's solution I came up with something like this:

for viewController in tabBarController?.viewControllers ?? [] {
    if let navigationVC = viewController as? UINavigationController, let rootVC = navigationVC.viewControllers.first {
        let _ = rootVC.view
    } else {
        let _ = viewController.view
    }
}

Add this to the ViewDidLoad of your first ViewController and should do the trick...

JRafaelM
  • 861
  • 2
  • 10
  • 23
7

Robert's answer above worked for me, but I had UINavigationControllers as my initial view controllers for each tab. Therefore I had to call

viewControllers.forEach { $0.view }

within my UINavigationControllers in order for their root view controllers to be loaded as well. Hope that helps Sam out.

mdaigle
  • 303
  • 3
  • 8
1

If you want to prepare both submissions and subcontrollers, you also have to call viewWillAppear(Bool):

tabBarController.viewControllers?.forEach {
    let _ = $0.view
    $0.viewWillAppear(true)
}

Ignoring this causes views will be under navigation and tab bars.

Agisight
  • 1,778
  • 1
  • 14
  • 15
0

UIViewController have loadViewIfNeeded() method https://developer.apple.com/documentation/uikit/uiviewcontroller/1621446-loadviewifneeded

  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/34154340) –  Apr 07 '23 at 15:58
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 11 '23 at 05:18