Swift Long Delay Between viewDidLoad and viewWillAppear

3.9k Views Asked by At

I'm encountering an problem where I am having a long delay when trying to present a ViewController. I am trying to display an upgrade alert when a user clicks on a UITableViewCell which requires premium access. In the ViewController being presented, I put debug code:

override func viewDidLoad() {
    super.viewDidLoad()

    println("\(NSDate()) viewDidLoad")
    // Set Navigation Title font and color
    self.navigationController?.navigationBar.titleTextAttributes = [NSFontAttributeName: UIFont(name: "UbuntuCondensed-Regular", size: 22)!,
        NSForegroundColorAttributeName: UIColor.whiteColor()]
    println("\(NSDate()) end of viewDidLoad")
}

override func viewWillAppear(animated: Bool) {
    println("\(NSDate()) before super.viewWillAppear(animated)")
    super.viewWillAppear(animated)
    println("\(NSDate()) after super.viewWillAppear(animated)")
}

override func viewDidAppear(animated: Bool) {
    println("\(NSDate()) before super.viewDidAppear(animated)")
    super.viewDidAppear(animated)

    println("\(NSDate()) after super.viewDidAppear(animated)")
}

The println statement resulted in:

2015-06-23 16:36:54 +0000 viewDidLoad
2015-06-23 16:36:54 +0000 end of viewDidLoad
2015-06-23 16:36:57 +0000 before super.viewWillAppear(animated)
2015-06-23 16:36:57 +0000 after super.viewWillAppear(animated)
2015-06-23 16:36:58 +0000 before super.viewDidAppear(animated)
2015-06-23 16:36:58 +0000 after super.viewDidAppear(animated)

As you can see there is a 3 second delay between the end of viewDidLoad and the start of viewWillAppear. I can't figure out why this is occurring. I am creating the views programmatically within the ViewController, so the storyboard is not being used here.

This is the code I have to present my ViewController:

// Create the upgrade view contorller
let upgradeVC = UpgradeViewController()
// Set the presentation context
self.providesPresentationContextTransitionStyle = true
self.definesPresentationContext = true
// Set the upgrade controller to be modal over current context
upgradeVC.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
// Show the view controller
self.navigationController?.presentViewController(upgradeVC, animated: true, completion: nil)
2

There are 2 best solutions below

3
On BEST ANSWER

Creating and presenting the view controller should be done on the main thread.

(When view updates are delayed, it nearly always means you're erroneously working on a background thread.)

1
On

I am putting this out there so people understand the viewDidLoad and viewDidAppear time delay is nothing you did wrong if you are in UITableViewController didSelectRowAt.

There is clearly a hidden async await background thread bug inside Swifts UITableViewController didSelectRowAt callback:

If your code looks something like this it may well lag 2 or 3 seconds in between viewDidLoad and viewDidAppear

class ViewControllerList: UITableViewController{
   override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)       
   {
        let storyBoard = UIStoryboard(name: "Display", bundle:nil)
        let displayView = storyBoard.instantiateViewController(withIdentifier: "ViewControllerDisplay") as! ViewControllerDisplay
        self.present(displayView, animated: true, completion: nil)
   }
}

(despite you doing nothing to deserve it)

this is how you speed it up in Swift 4

class ViewControllerList: UITableViewController{
   override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)       
   {
        DispatchQueue.global(qos: .background).async {
            // Background Thread
            DispatchQueue.main.async {
                // Run UI Updates or call completion block
                let storyBoard = UIStoryboard(name: "Display", bundle:nil)
                let displayView = storyBoard.instantiateViewController(withIdentifier: "ViewControllerDisplay") as! ViewControllerDisplay
                self.present(displayView, animated: true, completion: nil)
            }
        }
   }
}