Youssef Moawad
Youssef Moawad

Reputation: 2866

Presenting a Modal ViewController from a TableViewController lags

I have UITableViewController that needs to present a view controller modally when a cell is tapped. I'm using didSelectRowAt for this.

The modal view controller is a custom UIViewController subclass that has a loadFromStoryboard() class method to load it.

Sometimes when I tap the cell, the view controller is presented quickly without issue. However, other times it doesn't show until I, for instance, try to scroll on the tableview or tap another cell.

I'm guessing this is some sort of problem with threading. However, throughout my entire app, I never delegate a task to another thread or start another queue at all.

N.B.: I am using Swift 3.

Update

Here's the loadFromStoryboard() method:

class func loadFromStoryboard(particle: ParticleProtocol, isFavourite: Bool = false) -> ParticleDisplayViewController {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    if let viewController = storyboard.instantiateViewController(withIdentifier: "ParticleDisplayViewController") as? ParticleDisplayViewController {

        viewController.particle = particle
        viewController.isFavourite = isFavourite

        return viewController
    } else {
        fatalError("Can't find ParticleDisplayViewController in Main storyboard")
    }
}

And here is didSelectRowAt from my UITableViewController:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    switch indexPath.section {
    case 1:
        let isFavourite = ParticleStorageManager.standardModelParticleIsFavourite(index: indexPath.row)
        self.present(ParticleDisplayViewController.loadFromStoryboard(particle: standardModelParticles[indexPath.row], isFavourite: isFavourite), animated: true, completion: nil)
    case 0:
        let isFavourite = ParticleStorageManager.savedParticleIsFavourite(index: indexPath.row)
        self.present(ParticleDisplayViewController.loadFromStoryboard(particle: self.particles[indexPath.row], isFavourite: isFavourite), animated: true, completion: nil)
    default:
        self.contextKey = "AddingParticle"
        self.present(CreateParticleTableViewController.loadFromStoryboard(reciever: self), animated: true, completion: nil)
    }

}

ParicleStorageManager simply reads and writes data to the UserDefaults.

Here's viewDidLoad() from the modal view controller:

override func viewDidLoad() {
    self.view.backgroundColor = .clear()

    self.particleViewContainer.layoutIfNeeded()
    self.particleViewContainer.addSubview(ParticleView(position: CGPoint.zero, width: particleViewContainer.width, particle: self.particle, isFavourite: self.isFavourite))

    propertiesTableView.backgroundColor = UIColor.white().withAlphaComponent(0.3)
    propertiesTableView.layer.borderWidth = 1.5
    propertiesTableView.layer.borderColor = UIColor.black().cgColor
    self.propertiesTableView.blur()
}

Upvotes: 0

Views: 454

Answers (1)

daris mathew
daris mathew

Reputation: 429

Calling self.present from within func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) is the reason here as UIPresentationController may take time to find the layout from tableview row selection and causes a delay in presenting a new controller modally.

A better way to present is using the DispatchQueue on main thread. This way the delay can be avoided.

 DispatchQueue.main.async {
           //Your Presentation code should be called here.... 
   }

Upvotes: 1

Related Questions