Delay in presenting a modal view controller

IosObjective CIphoneModalviewcontroller

Ios Problem Overview


I have a tab bar based app. There are navigation controllers in all 5 tabs with instances of custom view controller setup properly as root view controllers. This loads just fine. A couple of these view controllers contain table views. I want to show a modal view controller to the user when they select a row in the table view. The (relevant part of) didSelectRowAtIndexPath delegate method looks as follows:

SampleSelectorViewController *sampleVC = [[SampleSelectorViewController alloc] init];
[self presentViewController:sampleVC animated:YES completion:NULL];

The modal view controller appears BUT it appears after a very noticeable delay. At times it even requires the user to tap the row a second time. A few things that I have already verified are:

  • Table view's didSelectRowAtIndexPath method is called when the user taps the row
  • The didSelectRowAtIndexPath method does not contain any blocking calls. There are no network operations being performed and the modal view controller's setup does not involve any processing intensive task. The data it displays is static.
  • If I push the new view controller onto the navigation stack (everything else remaining exactly same), it behaves perfectly without any delays. It is only when presented modally that the delay is encountered.

Any ideas/suggestions?

Ios Solutions


Solution 1 - Ios

It seems calling presentViewController:animated:completion from within tableView:didSelectRowAtIndexPath: is problematic. It's difficult to find anything that stands out when using the Time Profiler in Instruments, also. Sometimes my modal view comes up in less than a second and other times it takes 4s or even 9s.

I think it's related to the underlying UIPresentationController and layout, which is one of the few things I see when selecting the region of time between tapping on a row and seeing the modal presentation in the Time Profiler.

A Radar exists describing this issue: http://openradar.appspot.com/19563577

The workaround is simple but unsatisfying: delay the presentation slightly to avoid whatever contentious behavior is causing the slowdown.

dispatch_async(dispatch_get_main_queue(), ^{
   [self presentViewController:nav animated:YES completion:nil];
});

Solution 2 - Ios

If you call present(:animated:completion:) in tableView(:didSelectRowAt:), selectionStyle == .none for selected tableview cell and you’ve got this strange behavior then try to call tableView.deselectRow(at:animated:) before any operations in tableView(_:didSelectRowAt:).

Did it help?

Solution 3 - Ios

Swift 4: you can use as below.

DispatchQueue.main.async {
            let popUpVc = Utilities.viewController(name: "TwoBtnPopUpViewController", onStoryboard: "Login") as? TwoBtnPopUpViewController
            self.present(popUpVc!, animated: true, completion: nil)
        }

It works for me.

Solution 4 - Ios

I guess you also set the cell's selectionStyle to UITableViewCellSelectionStyleNone. I change to UITableViewCellSelectionStyleDefault and it work perfect.

Solution 5 - Ios

You should display it modally from your root vc (e.g: customTabBarRootViewController). save a reference, and use the reference controller to display it.

Solution 6 - Ios

I have also had this strange delay when presenting from tableView:didSelectRowAtIndexPath: looks like an Apple bug.

This solution seems to work well though.

CFRunLoopWakeUp(CFRunLoopGetCurrent()); // Fixes a bug where the main thread may be asleep, especially when using UITableViewCellSelectionStyleNone

Solution 7 - Ios

Solution in Swift 3

In the SampleSelectorViewController(the presented view controller) use the below code

DispatchQueue.global(qos: .background).async {

// Write your code

}

Solution 8 - Ios

The common problem with this behaviour is as follows:

one sets selectionStyle = .none for a cell in the tableView (it seems that it doesn't depend on UITableViewController subclassing as was written at http://openradar.appspot.com/19563577) and uses at the delegate method

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)

animating deselect

tableView.deselectRow(at: indexPath, animated: true)

which implies animation for non-animating cell.

In this case the subsequent view controller presentation has a delay.

There are some workaround solutions including dispatch_async on main thread, but it is better not to call deselectRow even without animation on unselectable cells in your code.

Solution 9 - Ios

As per @Y.Bonafons comment, In Swift, You can try like this, (for Swift 4.x & 5.0)

DispatchQueue.main.async {

                self.showAction() //Show what you need to present
            }

Solution 10 - Ios

Try this For swift version 5.2 you can use below code:

DispatchQueue.main.async(execute:{self.present(nav, animated: true)})

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNuman TariqView Question on Stackoverflow
Solution 1 - IosazsromejView Answer on Stackoverflow
Solution 2 - IosArtem KirillovView Answer on Stackoverflow
Solution 3 - IosArshad ShaikView Answer on Stackoverflow
Solution 4 - IosNeeeeeilView Answer on Stackoverflow
Solution 5 - IosGiladView Answer on Stackoverflow
Solution 6 - IostrapperView Answer on Stackoverflow
Solution 7 - IosKrishna VivekanandaView Answer on Stackoverflow
Solution 8 - IosmalexView Answer on Stackoverflow
Solution 9 - IosiHarshilView Answer on Stackoverflow
Solution 10 - IosHitesh RasalView Answer on Stackoverflow