Transitioning from one UIPopoverController to another is slow on iOS8 - ios

My app has multiple buttons each of which brings up a different UIPopoverController. We have 'passthroughViews' set so the buttons are still enabled while the popovers are up. Pressing one of the buttons while a popover is displayed dismisses the current popover and brings up the new one. The trouble is, this seems very slow on iOS8. The popovers come up and go away on their own just fine -- it's just when we switch from one to another that there is a pause between when the first one closes and next one starts to show. I'm calling these dismissPopoverAnimated and presentPopoverFromRect: calls back to back, so there is nothing going on between the two. I've tried setting 'animated' to NO for both of these but the pause still remains. Any help is greatly appreciated.

Rather than close the popover, re-purpose the same popover when the 2nd button is pressed. Move the location of the popover, on the screen and load the new content into it. Seems like that would be quicker and avoid whatever contention or latency issues you are experiencing switching from one modal view to the next (I suspect that is what the issue is). You'd lose the disappear/reappear animations, but it should be near instantaneous and provide a good user experience, because users don't really (in the long run) want to wait through animations to see their content when they push a new button anyway.

What's inside these popovers? If they're tied to something running on the main thread, then you are likely seeing that as your lag element. You might want to lean up your viewDidLoad and viewWillAppear methods. Try running largish processes on a background thread and updating it after appearing.
If you are using a core data store then you are likely using the primary context, which always runs on the main thread. Try caching those calls ahead of time, or run your fetches on a child thread and returning those to the main thread after the popover has loaded.

Try this code,
[UIView transitionWithView:pop1.contentViewController.view duration:0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[pop1 dismissPopoverAnimated:NO];
} completion:^(BOOL finished) {
[pop2 presentPopoverFromRect:btn.bounds inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:NO];
}];
hope it helps.

I had a similar issue that had my head banging on the problem for almost a day: the UIPopoverController was extremely slow to appear on occasion (sometimes it was sluggish, other time almost fine, other it was taking like 4" to appear...), and this happened only on iOs8 (iOs7 was always blink-fast), which leads me to believe that my solution might help you as well.
After much debugging I have come to the conclusion that the problem for me was connected the fact that I showed the popover within the
- (NSIndexPath *) tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;
method (but I would'n rule out that other similar cases exist).
My solution is running the presentPopoverFromRect: method (my logs showed it was the slow method) just after the willSelectRowAtIndexPath: method ended (as a matter of fact I crammed the whole popover "initialize and show" in the function to delay as well, to be on the safe side, and because my code was already like that).
This boils down to running the UIPopoverController initialization and display code in a block like this one:
dispatch_async(dispatch_get_main_queue(), ^() {
// Do the popover stuff here
});
Even if you are not using table, other similar problems might exist within iOs8 (because this is an Apple bug!), so I guess this might worth a try...
Hope it helps,
Cheers

Related

UINavigationController keeps displaying popped view

So in an iOS app I'm using a UINavigationController as the root view controller. I then push a few ViewControllers on the stack, let's call them A, B, C and D.
Now if I try to pop D from the stack, I sometimes * run into the following problem:
After calling popViewControllerAnimated, the view of the topmost view controller (D) remains. If I display the stack however, it is displayed correctly, i.e. A-B-C is displayed and D is gone. The pop method seems to do just what it's supposed to but the view does not reflect this.
I have tried various other approaches, (popToRootViewController, popToViewController) instead but the behaviour doesn't change (i.e. the stack is printed correctly but D's view remains). I have called setNeedsDisplay on all views that seem to make sense.
After popping D, I can still push and remove other view controllers. The stack reflects those changes, the view does not. Also, D's view remains responsive, i.e. it is not frozen and the app does behave correctly in the background. All views are very simple, there are no tabbed views or the like, just a couple of labels and buttons.
I have read a number of posts on SO and elsewhere about people having similar problems but none of the solutions seem to fit here. Does anyone have an idea why this happens?
*_ I haven't been able to figure out under which circumstances exactly. I first thought it was because I am popping D very soon after pushing it, but it also occasionally happens when there is more time between push and pop.
Only reason i can think of where this might happen is if you are not doing that in a main thread. If you are doing it after some network call, then do make sure you are going back to main thread. Sometimes, app won't crash if you do UI work on background thread but rather will behave like what you are seeing!
The problem seems to have been one of timing. As I mentioned, the push and pop operations (of D) sometimes do happen rather quickly after one another. Adding a delay of 2500 ms solved the problem. Adding 500 ms did not (always). Since neither is acceptable to me, I switched to a custom container view controller and therefore didn't spend a lot of time on figuring out what the minimum delay would be.
Just as sidenote: Changing from dispatch_async to dispatch_sync didn't have any effect. The delay seems to be necessary either way.
Thanks for everyone's help. I'm going to close this thread - if someone can provide a more complete answer as to why things are the way they are, please post it and I'll mark it as the correct answer then.

UITabBarController switch tab is slow at first time

I am working on an ipad project whose UITabBarController (it's also the root) has 5 tabs.
The second tab is a tableview where there are quite rich UI elements.
The problem is that everytime I launch the app and click the second tab, I would be blocked for 0.3 second to show the viewcontroller. However, after the first time enter this tab, it only takes me 0.03 to enter this tab again.
So I thought the ViewDidLoad cost too much, because I do a lot addSubView or reloadData there. So I add
[libraryVC viewDidLoad];
[libraryVC viewWillAppear:YES];
[libraryVC viewDidAppear:YES];
in application:didFinishLaunchingWithOptions, I think if I do this view load stuff before user enter the second tab, then there will be no block.
However after I tested this approach, I found the cost was not be reduced. So I guess the time cost may be used in the view render when first show this viewcontroller. When the viewcontroller's view has been rendered before, then the following show will be fast. But I have no idea to solve this problem.
I think this problem is very common when the viewcontroller's view is really complicated, so does anyone has an idea of the approach to solve this problem? Or does anyone can give a detail description of the reason why the block happens?
Thanks for any help!
Perhaps multithreading the time intensive methods/calls is the solution you are looking for. If you search "ios grand central dispatch" on Google, some great resources will be available. Apple's Grand Central Dispatch reference is one of the better pieces of documentation they have.

View transitions slowed down on adding OpenGL view

Facing a really, really weird problem with an OpenGL View we are using in our app to perform some custom animations. As soon as the Open GL View is added into the project, all native View animations slow down. And by slow down I don't mean a drop in frame rate. The animations are stutter-free, except much much MUCH slower than normal (like someone enabled "Toggle Slow Animations" in the Simulator).
This is affecting only view transitions animations, for example:
a. transitionFromView
b. presentViewController (iOS6, or presentModalViewController on earlier)
While regular UIView Animations, CABasicAnimation etc proceed at the regular pace.
I haven't seen anything like this, and the results honestly have to be seen to be believed. :) But any idea what the problem could be (I'm not sure which piece of the code would help you debug, and I'm unfortunately not in a position to share screenshots or video)
It seems like the animation gets stuck while loading the OpenGL View, debug the
Lifecycle methods like loadView, viewWillLoad. The loadview, etc. happens within the
transition animation, maybe you can solve the slow animation by sending most of the loading
code in to a custom method which you call in viewdidload or viewdidappear.
It does not interrupt any other animation because thats a totally new action in the queue.
Hope this helps!
Found the solution accidentally several days later.
The problem turned out to be much sillier and unrelated. It so happens that if you have a UIView beginAnimation block that is not closed properly, future animations get all wonky. This faultily coded animation happened to be triggered at more or less the same time as the OpenGL view was being initialized, which led to my erroneous belief that the OpenGL View was at the root of this.
Thanks for the help!

How to automatically load subviews for testing?

I'm writing an iOS app that has a problem on a view that's about 4 taps deep into the UINavigation stack. It's becoming a pain to have to repeatedly tap tap tap through the simulator to drill down to the UIViewController I need every time I want to run the thing.
Is there a way to automate this?
I tried just instantly calling [self tableView:self.tableView didSelectIndex... manually, however that blows up because data hasn't been loaded into the table yet...
I'd prefer something fast w/o a lot of overhead to it - otherwise it'll take more time to implement the solution than I'd save by not tapping the screen 4 times...
Thanks for any insight you guys can provide.
I do this all the time - in the appDelegate, I just add some code wrapped in a #ifdef that just makes the subview the initial view of the navigation controller. Once you get the subview working you can turn the ifdef off. Using the technique will save you lots of time - in fact I'm using it right now to add functionality to my app in the store.

UIViewController viewDidLoad vs. viewWillAppear: What is the proper division of labor?

I have always been a bit unclear on the type of tasks that should be assigned to viewDidLoad vs. viewWillAppear: in a UIViewController subclass.
e.g. I am doing an app where I have a UIViewController subclass hitting a server, getting data, feeding it to a view and then displaying that view. What are the pros and cons of doing this in viewDidLoad vs. viewWillAppear?
viewDidLoad is things you have to do once. viewWillAppear gets called every time the view appears. You should do things that you only have to do once in viewDidLoad - like setting your UILabel texts. However, you may want to modify a specific part of the view every time the user gets to view it, e.g. the iPod application scrolls the lyrics back to the top every time you go to the "Now Playing" view.
However, when you are loading things from a server, you also have to think about latency. If you pack all of your network communication into viewDidLoad or viewWillAppear, they will be executed before the user gets to see the view - possibly resulting a short freeze of your app. It may be good idea to first show the user an unpopulated view with an activity indicator of some sort. When you are done with your networking, which may take a second or two (or may even fail - who knows?), you can populate the view with your data. Good examples on how this could be done can be seen in various twitter clients. For example, when you view the author detail page in Twitterrific, the view only says "Loading..." until the network queries have completed.
It's important to note that using viewDidLoad for positioning is a bit risky and should be avoided since the bounds are not set. this may cause unexpected results (I had a variety of issues...)
This post describes quite well the different methods and what happens in each of them.
currently for one-time init and positioning I'm thinking of using viewDidAppear with a flag, if anyone has any other recommendation please let me know.
Initially used only ViewDidLoad with tableView. On testing with loss of Wifi, by setting device to airplane mode, realized that the table did not refresh with return of Wifi. In fact, there appears to be no way to refresh tableView on the device even by hitting the home button with background mode set to YES in -Info.plist.
My solution:
-(void) viewWillAppear: (BOOL) animated { [self.tableView reloadData];}
Depends, Do you need the data to be loaded each time you open the view? or only once?
Red : They don't require to change every time. Once they are loaded they stay as how they were.
Purple: They need to change over time or after you load each time. You don't want to see the same 3 suggested users to follow, it needs to be reloaded every time you come back to the screen. Their photos may get updated... you don't want to see a photo from 5 years ago...
viewDidLoad: Whatever processing you have that needs to be done once.
viewWilLAppear: Whatever processing that needs to change every time the page is loaded.
Labels, icons, button titles or most dataInputedByDeveloper usually don't change.
Names, photos, links, button status, lists (input Arrays for your tableViews or collectionView) or most dataInputedByUser usually do change.

Resources