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 answers

3
Aaron Brager 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
Mr Heelis 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)
            }
        }
   }
}