I'm looking for a technique to progressively load in the contents of a UIViewController to make an app feel "snappier". I noticed this issue when pushing a viewcontroller onto the stack there's a noticeable delay while waiting for it to push in. The UIViewController's View has some complex subviews with transparency. I'm wondering if I create them after viewDidAppear and 'fade' them in, then the transition will appear much smoother.
I noticed a similar effect in Apple's Trailers app. When tapping a movie in that app the detail view pushes in and the contents load after the fact. Granted part of that delay is because they are downloading the details before showing them, but it seems like they always fadein that large image whether it's been downloaded already or not.
Has anyone had much success with this or with improving UIViewController loads in general.
Before you start making changes in an effort to improve performance, use Instruments to profile your app and find out where the problem really is. Is it in drawing the complex subviews? Is it in loading the data? The only way to know is to measure.
There's no reason you couldn't do as you propose -- have the view controller create/load its main view and then add the complex subviews afterward. Your view controller can add and remove subviews at will. Will that make the app feel snappier? It might -- it's similar to the default image strategy Apple built into iOS, where the OS loads a picture of your interface to make the device seem responsive, and then substitutes the real interface once that's ready. On the other hand, if the user still has to wait for the complex subviews to be created before the view is useful, seeing the rest of the view might not help much.
Another possibility (again, after measuring) might be to create the views before the user needs them. This runs counter to the lazy initialization that iOS apps commonly use to conserve memory and power, but if you know that you're going to need the views and you can expect a lull in user activity before they're needed, it could be a good way to increase the app's apparent speed. All you need to do to get a view controller to create/load its view is to access its view property.
Related
I'm an Android developer, I started learning iOS development lately and I've been wondering about how to manage the UIViewControllers.
In Android, when you don't need an activity anymore, it is better to remove it from the application stack, for example a login screen is only needed when the user logs in, after that there is no need for that screen so it is better to destroy it and remove it from the stack, but what about iOS? Do you have to manage view controllers the same way as activities? or does the system automatically handle the views in the background?
It would be great if you can link some reference to read more about the way View-controllers are handled in the background, I'm trying to learn the best practices
Short answer: No, let ARC handle it
ARC handles the release from memory automatically when you pop a view from a navigation stack, so if you go "back" (pop) you normally don't need to worry about it.
But, sometimes you have a big navigation stacks with many different views with a lot of data/images/etc that will eat memory. In those cases you could separate your app into different flows and instead replace the root view controller of the main window with the new flow every time you want to change. The old flow should be released from memory automatically, unless its connected to another object (like a singleton).
Everyone has seen the classic didFinishLaunchingMethod run amok.
Well now that we have additional things to consult when starting up like CloudKit, that are, to make things worse, asynchronous, the app delegate seems like the wrong place to do even the most basic stuff like asking if they have accounts and establishing syncing, or grabbing a snapshot.
I hate the idea that those things would go into the first controller that the app would launch, flashes me back to 4GL tinkertoys from days of yore.
Yet, we have to honor the flows of the storyboards. I have found nothing searching around on this. And sadly the most extensive Apple example, Lister, is not a great source for best practices.
It's suitable for the app delegate to trigger the start of this work, but not to handle the results. Often you want some way to display progress / errors / request user info. So, having some form of 'splash' view controller which handles the transition from your launch image into this process and controls the flow into the main app is handy. Generally the logic for this kind of thing is reusable in other situations so that part should be in some other controller class. The storyboard can make the splash VC the initial controller and the app delegate can create and pass it the data controller class which deals with the logic and updates the VC (it's delegate) with the results. Often the splash VC will then pass the data controller on to the subsequent VC it displays, though that isn't required of course.
I have been working on an iOS, OpenGL-based app for the past few months. During this time, I have created both the main UIWindow and a single UIView in code, as opposed to using a storyboard. An important item to note is that I create an instance of EAGLView (used in many Apple examples), which inherits from UIView.
The code base I am working with is quite extensive, and among other things, it uses a separate rendering thread. I'll come back to this point near the end of this post.
With this in mind, I am now at the point that I want to add native UI support. To do this, I am using a storyboard (for the first time). My current setup consists of a main/root view with two buttons. Each button uses a modal segue to place a new view on the screen.
To reuse as much code as possible, I have specified that the views I segue to are of type EAGLView (as opposed to UIView). The only change I've had to make is that instead of initializing with "initWithFrame", I now initialize with "initWithCoder".
Other than moving to a storyboard, nothing else in the code base has changed. However, when I segue to an EAGLView, nothing renders -- all I see is white. I am hesitant to use GLKit because it duplicates much of the functionality I have already written (I had everything rendering just fine prior to using a storyboard). In addition, GLKit provides a callback for rendering, whereas, I have a separate render thread.
My scenario sounds a lot like this post:
OpenGL iOS view does not paint
I have GL error checks for every call (or for every group of calls), and no errors are being reported. What's even stranger is that when I capture an OpenGL ES frame for debugging (in Xcode), the debugger actually shows the content I expect to see.
Any ideas here? I am stumped.
Please try the following:
Verify that you stop rendering in the view that you're segueing from (stopping times etc.) - this view is still alive since you only pushed a new EAGLView on top of it.
Use XCode's OpenGL ES Frame capture to debug your OpenGL state in the new view. Verify that you're not missing binding to textures or other objects.
If the above doesn't work - write the simplest rendering possible (simple quad, for example) and debug that code.
I have this problem with performance of my iPad app..
For developing, I use MonoDevelop, which takes care of Garbage collecting. Still my questions are rather generic, I'd say.
OK, I use TabBarController with 5 NavigationControllers. Inside nav controllers there are some controllers, whose views are TableViews or ScrollViews. Next child is always just regular view.
I have a few questions:
1) TableViews never scroll smoothly. I have some alpha transparency, but since I did my graphics in Photoshop and not programmatically, this transparency should not cause much problems. It doesn't matter whether I have few or many results in table.
On the other hand, I have ScrollView which serves same purpose, i.e. to be a table with different layout and buttons have Photoshop generated transparency as well. It works perfectly.
For tables I applied DequeueReusableCell() which works fine (I see that memory usage is not increasing after scrolling). So why would tables scroll so jerky?
2) My app supports rotation. When I scroll table or scrollView and simultaneously tilt the device a bit, I get maybe 1 or 2 FPS. What is the best way to implement rotation? As I understand, ShouldAutorotateToInterfaceOrientation has to be overridden in all controllers in NavigationController chain. Also, I need to add observer in View I want some changes to happen. Do I have to use BeginGeneratingDeviceOrientationNotifications() in all views or is it enough to do it in Main.cs? Maybe this slows it down?
3) After some time app starts getting memory warnings and then crashes eventually. I tried to read logs and run app with Instruments, but can't find the cause of crash.
4) What exactly happens to a View popped from NavigationController stack? I can't reuse it. But could it be that Monotouch (or me) doesn't dispose it correctly?
I have almost same app for iPhone without support for rotation which never crashes. I think I'm doing something wrong with this rotation, but I'm not sure what.
Any help will be appreciated the most. So, thank you in advance.
Regards
1 - transparencies are always a problem. Even if you're not rendering the images in code, the phone still needs to do the compositing of the image, and that may take a lot of time. UITableViews have to calculate the final composite image every time a new cell is displayed, or the table is scrolled, while UIScrollViews can calculate only once, since the image won't change. So be very careful about it, turn the transparency off, and check if performance improves.
2 - You shouldn't need to notify every uiview in your application. Receive the notification in the controllers that you want to update only, like for example if you want to rearrange items in the UIViewControllers view.
3 - you have one (or many) memory leaks. My guess is that MonoTouch probably can't garbage collect UIViews or UIViewControllers, because they're still being linked from somewhere in UIKit, like a UINavigationController
4 - UIViews are not disposed by UIKit until the app gets a memory warning notification.
Like Eduardo said, alpha transparency in Views comes at a price. There are some tools that you can use to identify the bottlenecks discussed in these WWDC 2011 talks from:
https://developer.apple.com/videos/wwdc/2011/
iOS Performance and Power Optimization with Instruments
Understanding UIKit Rendering
In the "Debug" menu of the iOS simulator you can find various debugging tools that will color different regions of the screen indicating where some problematic rendering is taking place. The WWDC 2011 talks show what you can do to fix those problems.
For your memory problems, it is very likely that you have something pointing out to your objects around, so you need to make sure those objects are gone. While we currently are not shipping our new profiler for MonoTouch that can show the source of the problem, I wrote a "poor man's" debug utility that will help you narrow down which objects are alive. It is available here:
http://tirania.org/tmp/HttpDebug.cs
Call HttpDebug.Start () from your application and as you run, connect with a web browser to http://localhost:5000 to get a list of live Objective-C objects surfaced to C#. The tool is not perfect and shows a lot of irrelevant data, but it would at least give you an idea of what is going on.
When using the Ti.UI.iPad.SplitWindow what is the best(cleanest looking) way to update the detailView?
The options I can think of are changing the positions of elements in the detailView event or to show()/hide() vs open()/close() on an orientationchange event. I know that using the native UI components on the iPad should dynamically update to the layout width/height of the iPad but in my case the content on each detailView will have it's child objects positions updated on orientationchange. I'm just trying to get the smoothest from your all experiences. Even if I have to build custom animations I just want to start this correct from the beginning so no current code exists yet. Thus none included.
I'm hoping this isn't a duplicate as I searched before I ask but there are no Titanium based questions on this topic I can find. Possible but still different to what I'm asking.
The smoothest experience will be delivered by changing the least. I don't know what animations you are envisioning, but I would nudge you towards keeping it simple.
Here's a quick example of an orientation change in an iPad app I built recently. I had a bunch of images in a view with layout: 'horizontal'. Due to a nice bug, the images wrapped automatically. When the user reoriented the device, I animated the width of the view, and the images automatically and animatedly resorted themselves.
I've also had some clients at a large corporation get their hearts set on really complicated changes to the layout whenever the user reoriented the device. This resulted in a really unsatisfactory app that took 10-20 seconds to reorient. We made a lot of optimizations, and a lot of improvements in both their code and the underlying framework, but the heart of the problem was the complex design.
Take the time to consider if you really need complicated changes every time the user reorients, and how much benefit you are offering to your users. Also consider the cost to the user (not just to the device) of presenting them with a new UI.
Past that, you're probably not going to get too many answers until you put some experimentation in to this. If you come back with some code and some questions to go along with it, I can reformulate my answer to better pinpoint your situation.
Hope this helps! -Dawson