Speed up UI loading from NIBs on the iPhone - iphone

First up, i realize this application has some design issues and while rewriting a huge chunk of it would probably solve my issues, I'm looking for a way to make things faster right now.
Basically I've got
viewController = [[MyViewController alloc] initWithNibName:nil bundle:nil];
viewController.view;
where MyViewController.xib is a rather complex nib file with a lot of intertwined controllers and views, some of which of course load their views and hierarchies from other nibs, but certainly not all. This takes around 7 seconds to load, which is a really long time considering this is an iPhone application.
The reason for forcing the view to load is that I'm also doing a some network requests in a parallel thread and once those have finished I'd like to set up quite a few things with these views.
My question is: how do I find out which parts of my nib are taking so long and what would be the best strategy to optimize this without completely rewriting the whole app (for now)?

The first thing to do is not to assume that the nib loading is the bottleneck without direct evidence that it is. Nib loading is highly optimized and very efficient. It is more likely that your bottleneck is the network request than the nibs. Use Instruments to get concrete data about where the app is spending its time before you do anything.
Assuming it is the nibs, Andiih answer is the best for profiling but it sounds to me like you've really got a design issue.
It sounds like you need to break your big nib up into smaller nibs.
Its common to have one view per nib. For example suppose you had an app that had a tabbar with five tabs. Then each tab had a table view which would open a detail view. In the normal setup, you would have 11 separate nibs. One nib would define the tabbar, one nib for each tab's view and then one nib per detail view. When the app started, only the nib for the tabbar and the first visible tab would load so you would only load two of the 11 nibs to start.
To optimize, the first thing to do is to break it down into the smallest possible individual nibs. A nib only loads when needed. You should place the functionality throughout your nibs such that you don't load the nib if its view is not immediately displayed.
Nibs are just lightweight data files so don't be afraid to create nibs that 99% identical. For example, I often use separate views for each portrait and landscape view. For the user's perspective, it's one view but I have three separate nibs. I do this in cases when its easy to use an entirely separate view than to rotate a single complex view. Each nib is loaded when when its orientation is used. If the orientation never changes, it's never loaded.
If you have a complex interface which changes significantly depending on a network request, it will be faster at runtime to have separate nibs for each variation than it will be to cram all the functionality into one nib.

I have no idea if this would really work, but you could put logging statements in initWithCoder in each controller which will be called as each sub-xib loads. That might give you some clues.
I guess instruments don't give you anything useful ?

Related

Is it expensive to continuously dealloc and alloc in Objective C?

I have an iPhone app that has a 4 option menu, and allows the user to switch between view controllers quickly. So I thought to make the experience smoother, every time the user switches between view controllers, the from view controller is released right away, and the to allocated. And the user will most likely be doing a lot of switching. Is there a better way to handle memory here than to keep releasing and allocating the same view controllers over and over again?
View controllers aren't expensive. It is ok to alloc and release them. However the views can be expensive. When memory is low, the system tries to unload the views of the view controllers which are currently not visible. Your app should always be aware of that. Release expensive objects in viewDidUnload, i.e. IBOutlets and data that can be recreated.
If you experience performance issues you should hold all 4 view controllers in memory. So the views will be loaded faster. iOS takes care of unloading the not visible views (when appropriate).
If it's the user doing the switching, time spent in dealloc and/or alloc is completely insignificant, bar any extremely time-consuming operations like loading tens/hundreds of images, etc.
In short, both an on-demand and a cached solution will have some tiny advantage over the other. Your users will not notice the difference though.
It sounds like you might have been better off with a tab bar app?
If memory is your main concern then it sounds like you will be loading and unloading a lot which will be a slower experience for the end-user.
If you use a tab bar controller then the views in unused tabs will be automagically unloaded if memory is needed. and loaded again if/when necessary.

view swapping techniques

I want to hear developers opinions on the best way to swap views on the iphone.
For example, I have a tab bar and one of its tabs defaults to a login view. When The user logs in the view changes to a logged in view.
I was going to just use one view controller and have all the content in one xib hiding and showing content as needed but this seems in no way elegant.
Secondly I was considering having one viewcontroller and simply swapping the xib. I'm a litle reluctant to try this as I've read in an article or 2 that it can lead to memory leaks.
Finally I was considering using 2 view controllers with with 2 seperate xibs. My gut tells me this would probably be the "proper" solution but I so far have failed to hunt down any sample code on the correct way to do it.
Can you offer advice on the best way to solve this problem?
Is there a technique that I have not listed?
Thanks.
I would keep the logic for which view to show in the view controller. The XIB is the view itself, and should have no objects in it that are transient or not always visible for that particular view.
Your second approach (of swapping the views) seems to be the right approach to me, and is always something I, personally, do in these situations. I am not aware of any memory issues if you do it right (remove from superview, followed by loading the new view as a subview of the controller's view). You could perform any custom initialization once the new XIB has been loaded and before showing it to the user.
Multiple view controllers just seems superfluous as then you would ideally require another top level controller to manage the two view controllers.

iPhone best design for 70 different views?

I am new to iPhone development... trying to figure out the best design for 70+ views. Do I have 1 Navcontroller and 70 views or what?
I originally thought I would have about 10 XIBs each with their own NavController and views, but I haven't found anyone that seems to think this is correct or not.
I think I understand the iPhone does not handle the memory dealloc by itself so I am assuming that will be a bit choice on how to make this work.
If you are going to implement 70+ views means you have to use both the navigation controller as well as tabbar controller. Then only the user can easily access all the views. If you are using 1 navigation controller and 70+ views means it is very difficult for the user to view all the views.
If you would like to design your views graphically using Interface Builder (built into Xcode4 or separate app for Xcode 3 and prior), I would just have a UINavigationController in your first xib (one with the UIWindow). You can then design each of your other views separately, in their own xib file and load them and push them onto the navigation stack as necessary.
Your understanding is correct; iOS does not support automatic garbage collection, although there is a pretty established paradigm of how to allocate and release memory as needed to avoid memory leaks. 70 views in an iPhone app is quite a bit, but it should be fine in theory, although I can see there being issues if the user has to drill down quite a ways in the hierarchy and each successive view eating up more memory.

iPhone Application: Overall Application Hierarchy & Architecture

I have been struggling a little with my first real iPhone application and wanted to get some advice on how this should be structured. I am looking for some best practices in terms of creating UI components and linking them together to create the application flow (create views/controllers programmatically vs. with Interface Builder, etc...).
Overview:
I need to show a "Login" view on application start up.
--Show "Signup" view if they click the sign up button.
Once logged in... I have a TabBarController loading 4 views. These 4 views will have to load sub-views (master-detail like).
My question is:
1) What is the best way to piece this navigation structure together? Create each view as a .xib with a corresponding ViewController? How are these glued together?
2) How should I handle the Login/Sign up navigation, no TabBar should be shown on start, but will need it after authenticating the user.
Bonus Point) Are there documented best practices for this kind of stuff? I have been hacking together some workable code, but I got very lost and want to start over doing it the correct way.
I know this may be a little confusing, all and any help is much appreciated.
EDIT: For the Login view on top of the tab bar I used this, pretty simple.
LoginViewController *loginViewController = [[LoginViewController alloc] init];
[loginViewController initWithNibName:#"Login" bundle:nil];
[self.tabBarController presentModalViewController:loginViewController animated:YES];
When you create a new tab bar based application in XCode, you are pretty much already set up the way you would like - there's a main XIB that loads views for each tab from separate XIB files. You have one XIB per tab. Note that as you change types or add tabs you need to specify the proper view controller type in both the XIB with the tab bar, and in the XIB that you use to create your view!
As for the login view, a common approach is to use the tab bar as above, but in the app delegate applicationDidFinishLaunching method present a modal view controller that shows the login screen. The modal controller hides the tab bar and everything else until they are done, then it can be dismissed.
1) What is the best way to piece this navigation structure together? Create each view as a .xib with a corresponding ViewController? How are these glued together?
Use UINavigationController and push your custom views onto the navigation stack as needed. Check out the example Navigation Controller application via Xcode's New Project option to get a feel for how this works.
2) How should I handle the Login/Sign up navigation, no TabBar should be shown on start, but will need it after authenticating the user.
Set up a view for login (I would use a UITableView with one section containing two rows for username and password, but that's my own preference). Set up a second, separate view for sign-up fields (again, I would use a UITableView for this, to keep the layout clean and consistent).
Perhaps use a view animation to pop up the tab bar after successful authentication.
Bonus Point) Are there documented best practices for this kind of stuff? I have been hacking together some workable code, but I got very lost and want to start over doing it the correct way.
You'll end up rewriting your project several times — which is a good thing. Do check out Apple's sample applications (available from the iPhone ADC site) as these contain several "best practice" ways of using several of the UIKit components. As to putting together a larger application, keep your design as simple as possible and reuse as much of Apple's UI components as possible. You can always customize later.
In my opinion, only Cocoa programming examples and very simple applications are suitable for a single nib file. Otherwise you should spread your interface components across multiple nibs. This means each nib is smaller and when loaded into memory will only load those components as necessary. This will improve performance in your application and can help logically organize your program and make it easier to debug when issues arise.
In my tabbar apps I use MainWindow.xib to contain the main window and tabbar but I break up each tab into a seperate nib for the reasons above.
Apple offers the following guidelines:
When creating your nib files, try to keep the following guidelines in mind:
Design your nib files with lazy loading in mind. Plan on loading nib files that contain only those objects you need right away.
In the main nib file for a Mac OS X application, consider storing only the application menu bar and an optional application delegate object in the nib file. Avoid including any windows or user-interface elements that will not be used until after the application has launched. Instead, place those resources in separate nib files and load them as needed after launch.
Store repeated user-interface components (such as document windows) in separate nib files.
For a window or menu that is used only occasionally, store it in a separate nib file. By storing it in a separate nib file, you load the resource into memory only if it is actually used.
For more information you can visit:
http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4

Multiple Views within one XIB - iPhone SDK

I have been spending time learning how to use the iPhone SDK. I've read "Beginning iPhone Development: Exploring the iPhone SDK" from cover to cover and I've never seen an example of multiple views within one XIB.
To illustrate what I mean, here is a screen shot of a XIB with the simple configuration of what I'm referring to:
alt text http://theopensourceu.com/wp-content/uploads/2009/04/one-xib-multiple-views.png
I figure that there has to be a very specific reason that I've never seen this. In Apple's examples and in all of my readings thus far, multiple XIBs are used with only a single 'view' (and sometimes the Navigation Controller or a Tab Bar Controller, etc). What is the reason for this? Should I avoid multiple views inside a XIB? What are the advantages or disadvantages to to either method?
Thank you in advance
It's a question of memory optimization and loading times. If you put all your views in one XIB, then when your application launches, it has to load the entire XIB into memory and construct all of the objects for all of the controls, and this takes a non-trivial amount of time.
If instead you separate your views into separate XIBs, then your app will start up much faster, because only the XIB containing the initial view will be loaded, and it will also use less memory at first. Then, when the view changes, you can load the XIB containing the new view lazily. This will incur a minor hitch when opening a view for the first time. If you're really trying to optimize memory use, you can also unload the previous view when switching views, but I wouldn't recommend this, as this will incur a hitch every time you switch views, instead of just the first time you switch to any given view.
Following up on the previous answer, there are some times when you would like to load multiple views at the same time. Here's an example: You are displaying a report with multiple pages and you're going to use a UIScrollView to manage them. When the user is done browsing the report, he will close the report which will dismiss the view.
Create a UIScrollView in a XIB along with a UIView for each page you need. Since the UIViews are part of the XIB, they will be loaded into memory together, all at once, when the report is opened. Create two UIViewControllers and use them to display the page being viewed and the one being scrolled to. As the user moves through the pages, re-use the UIViewController on the page being scrolled away from to hold the page being scrolled to.
This will ensure great performance while the user is flipping through the pages. It loads all the pages at once up front into memory. I only uses two UIViewControllers, and it just changes which views are in them and moves them around.
This also has the great benefit of having all of the pages in one XIB. It makes it easier to edit, and quicker to load than separate XIB's. You just have to make sure you have the memory to load all the pages at once. If it's static content (such as in my case) it's a great way to go.
If you're looking for a good example of how to do this, I found this resource to be an excellent starting point:
http://cocoawithlove.com/2009/01/multiple-virtual-pages-in-uiscrollview.html
This is a warning to anyone trying to implement landscape and portrait with two views in a single XIB (iOS 4 with Xcode 4). The primary disadvantage of having two views in a single XIB–for me–was that you can only connect a single UIOutlet object in a XIB to a single UIOutlet object in a view controller.
So, for example, if you have a XIB with a view for landscape and a view for portrait, and both views contain the same interface objects in different positions (such as a UILabel in landscape and a UILabel in portrait). It is not possible to link the UILabel in your portrait view and the UILabel object in the landscape view to a single UILabel object in the view controller at the same time.
I find this a disappointment, as the iOS UIViewController documentation (iOS 4.3) suggested that I could implement custom landscape and portrait views by switching between two views programmatically as the screen rotates.
After spending quite some time to figure out how to do this, I discovered that it is possible to have two different views attached to a single view controller, but you need to have outlets for both views. For example, in my view controller, I have two UILabel objects (one to connect to a UILabel in the portrait view; one to connect to a UILabel in the landscape view). In my code, every time I update the landscape outlet, I also update the portrait landscape.
Not very elegant, but it works, and as this is for a simple view with one screen, it won't use up too much memory to have have all the UI objects duplicated in the controller and views. I wouldn't create a project that did it that way again, but it was a good enough work-around for that project.
One reason I place multiple views in one xib is because unlike storyboard xibs don't allow placing header and footer in the table view itself. So I create to separate view for header and footer view and assign them in viewDidLoad.