Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slow performance for presentViewController - depends on complexity of presentING controller?

I am presenting a view controller:

SCAAboutController2 *controller = [[SCAAboutController2 alloc] initWithNibName:nil bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
[self presentViewController:navController animated:YES completion:nil];

The device hangs for 3-4 seconds before presenting. I have attempted to diagnose this using Instruments, but it seems most of the time is spent in main -

enter image description here

Here is the same profile but with System Libraries unhidden:

enter image description here

None of these messages are recognizable to me, so I'm not sure how to start debugging my performance issue.

I read elsewhere that I should check that the main code is executing on the main thread. However, the following change is not improving anything:

dispatch_async(dispatch_get_main_queue(), ^{
        SCAAboutController2 *controller = [[SCAAboutController2 alloc] initWithNibName:nil bundle:nil];
        UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
        [self presentViewController:navController animated:YES completion:nil];
    });

I've quickly run out of ideas on how to progress. How might I investigate further, and/or what might be the root cause of the slow presentation?

Edit

Some confusing discoveries:

  • I've removed all code from the presented view controller. The performance is unaffected.
  • I have another controller which I present from the same place via a different button. It is equally slow.
  • the presentinging controller has quite a lot of subviews and constraints - even some child view controllers. Removing the code that populates these resolves the issue.
  • nothing is added in the viewWillDisappear of the presenting controller.

Edit 2

I have discovered that the issues centers around a series of layout constraints I add in the main (presenting) controller. Specifically, I loop through some child controllers (of type teamController) and add the constraint:

[self.browser addConstraint:[NSLayoutConstraint constraintWithItem:teamController.view
                                                         attribute:NSLayoutAttributeWidth
                                                         relatedBy:NSLayoutRelationEqual
                                                            toItem:self.browser
                                                         attribute:NSLayoutAttributeWidth
                                                        multiplier:1
                                                          constant:0]];

There are only 10 child controllers. Also strange: I have no such issues if I use the following instead:

[self.browser.contentView addConstraint:[NSLayoutConstraint constraintWithItem:teamController.view
                                                                     attribute:NSLayoutAttributeWidth
                                                                     relatedBy:NSLayoutRelationEqual
                                                                        toItem:nil
                                                                     attribute:NSLayoutAttributeNotAnAttribute
                                                                    multiplier:1
                                                                      constant:200]];

I am still very confused as to why these constraints would cause the presentation of another modal to hang, and why one variation of the constraint behaves drastically differently to the other.

like image 286
Ben Packard Avatar asked Mar 23 '14 00:03

Ben Packard


2 Answers

Not sure this was the original author's problem but here is something that solved a similar problem for me: I was trying to present a view from didSelectRowAtIndexPath and I had to call deselectRowAtIndexPath before. If this may help someone...

like image 156
vib Avatar answered Nov 03 '22 23:11

vib


Your app is unresponsive because of several add and remove operation on a set. If you do any heavy processing on main thread the app gets block and becomes unresponsive.

Short ans is you have a loop which is adding objects in a set and its doing that on the main thread which is making your app slow.

If you look at your instruments the view loading buttons and rendering is pretty fast. initWithFrame , viewDidLoad is taking less than 4% of overall of time. The majority of the time is taken by NSISVairable release and retain which is done around 500 times. So you are doing something with your collection object and probably its in a loop. retain and release takes time and should not be done on main thread.

Simple solution is :

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  // do all the heavy lifting here in background thread. 
}

Why does the following code does not improve anything :

dispatch_async(dispatch_get_main_queue(), ^{
        SCAAboutController2 *controller = [[SCAAboutController2 alloc] initWithNibName:nil bundle:nil];
        UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
        [self presentViewController:navController animated:YES completion:nil];
    });

because you are already doing this stuff in main thread and you need to call main_queue on in background thread. You should not do any UI stuff on background thread.

like image 7
Kunal Balani Avatar answered Nov 04 '22 00:11

Kunal Balani