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.
Related
I have a very large form to build in my ipad application and I'm note sure which approach( between create multiple views in or multiple viewcontrollers ) to follow. Well, I have decided to split may form in logical sections, so I want use a splitviewcontroller with a root( a tableviewcontroller with the sections) and multipleviecontrollers for each sections. When the user select a row in tableview I will show the correspondent viewcontroller. I'm saving a reference for each viewcontroller in my app_delegate and the app_delegate also is the responsible for change the viewcontrollers. Is this the best approach? There is other approach to follow? About the multiple view I was thinking to put multiple view in the same xib file and then choose based in tag as the use tap the row in rootviewcontroller's tableview.
Thanks in advance. And sorry for my bad english.. Learning!
I will say this on the subject: currently, having multiple view controllers on the screen at the same time can be problematic if you're not using one of Apple's existing classes, such as a UISplitViewController.
The main issue is that important events your view controllers will want to respond to (rotation events, etc) won't be passed down to them. It's not a huge pain, it's just something to need to take into account - you'd typically create your own parent view controller that could pass these events down to its children.
Now, you are using a split view controller, so alls well on that front. There is no provided way for detail and master controllers in a split view controller to communicate with each other, but Apple recommend you employ a standard delegation pattern. If your application is fairly simple this could certainly happen in your app delegate as you do now.
If you're targeting iOS 5 only there are some changes that are relevant regarding multiple controllers on the screen at the same time, but I can't discuss them on here because of the NDA. You should go to Apple's developer forums (devforums.apple.com) to learnmore.
Sounds like I'm trying to do the same thing as you (large insurance forms here, how about your project?) Unfortunately I can't help out as you're a bit ahead of me. I've been able to flip back and forth between 8 detail views by tapping on the 8 rows in my UITableViewController, without keeping a reference to either the current or previous one anywhere. The data I enter into various TextFields stays where it should.
I currently have a xxxViewController.h/.m and corresponding .xib file for each detail view. That's an awful lot of code, but I couldn't see any other way to do it. Now I'm having a problem getting my button pressed handlers to fire. Also I've still got to put a database behind these screens.
Were you able to overcome your issue?
Thanks,
Jeff in Alabama
I've seen a lot of posts and videos on switching views and many of them have vastly different approaches. Some swap the entire view (via a delegate class), some use presentModalViewController:animated:, etc.
So I ask: what is the best, cleanest, and most memory-friendly way to switch views? (I use view switching as a way to show completely new information that might be on the screen for a long time, not a temporary notice.)
Thanks,
Derek
There is no one answer to this question. It depends on the structure of your application, the UI you want to present and how you want the transition to look to the user. In terms of memory, what you do with the old view is more important than how you present the new view.
For example, if your root view switches (occasionally) between two other views, you can present them modally, or with a navigation controller, but when one is not displayed you might want to release/destroy it to save resources. (Actually, if you might switch back, you can keep the non-displayed view around and only release it if you get a memory warning.)
I have a view that contains a UITableView and a UILabel which works perfectly as far as I can tell. I really don't want to manage the UIView and UITableView with the same controller as the UITableViewController handles a lot of housekeeping and according to the documentation:
If the view to be managed is a
composite view in which a table view
is one of multiple subviews, you must
use a custom subclass of
UIViewController to manage the table
view (and other views). Do not use a
UITableViewController object because
this controller class sizes the table
view to fill the screen between the
navigation bar and the tab bar (if
either are present).
Why does Apple warn against using it and what will happen if I ignore this warning?
Update: Originally I quoted the following from the Apple Documentation:
You should not use view
controllers to manage views that fill
only a part of their window—that is,
only part of the area defined by the
application content rectangle. If you
want to have an interface composed of
several smaller views, embed them all
in a single root view and manage that
view with your view controller.
While this issue is probably related to why UITableViewController was designed to be fullscreen, it isn't exactly the same issue.
The major practical reason to use only one view controller per screen is because that is the only way to manage navigation.
For example, suppose you have screen that has two separate view controllers and you load it with the navigation controller. Which of the two view controllers do you push and how do you load and reference the second one? (Not to mention the overhead of coordinating the two separate controllers simultaneously.)
I don't think using a single custom controller is a big of a hassle as you think.
Remember, there is no need for the TableviewDataSource and the TableViewDelegate to be in the actual controller. The Apple templates just do that for convenience. You can put the methods implementing both protocol in one class or separate them each into there own class. Then you simply link them up with the table in your custom controller. That way, all the custom controller has to do is manage the frame of tableview itself. All the configuration and data management will be in separate and self-contained objects. The custom control can easily message them if you need data from the other UI elements.
This kind of flexibility, customization and encapsulation is why the delegate design pattern is used in the first place. You can customize the heck out of anything without having to create one monster class that does everything. Instead, you just pop in a delegate module and go.
Edit01: Response to comment
If I understand your layout correctly, your problem is that the UITableViewController is hardwired to set the table to fill the available view. Most of the time the tableview is the top view itself and that works. The main function of the UITableViewController is to position the table so if you're using a non-standard layout, you don't need it. You can just use a generic view controller and let the nib set the table's frame (or do it programmatically). Like I said, its easy to think that the delegate and datasource methods have to be in the controller but they don't. You should just get rid of the tableViewController all together because it serves no purpose in your particular design.
To me, the important detail in Apple's documentation is that they advise you not to use "view controllers [i.e., instances of UIViewController or its subclasses] to manage views that fill only a part of their window". There is nothing wrong with using several (custom) controllers for non-fullscreen views, they just should not be UIViewController objects.
UIViewController expects that its view takes up the entire screen and if it doesn't, you might get strange results. The view controller resizes the view to fit the window (minus navigation bars and toolbars) when it appears, it manages device orientation (which is hard to apply correctly if its view does not take up the entire screen) etc. So given how UIViewController works, I think there is merit to Apple's advice.
However, that doesn't mean that you can't write your own controller classes to manage your subviews. Besides the things I mentioned above, interacting with tab bar and navigation controllers, and receiving memory warnings, there isn't really much that UIViewController does. You could just write your custom controller class (subclassed from NSObject), instantiate it in your "normal" fullscreen view controller and let it handle the interaction with your view.
The only problem I see is the responder chain. A view controller is part of the responder chain so that touch events that your views don't handle get forwarded to the view controller. As I see it, there is no easy way to place your custom controller in the responder chain. I don't know if this is relevant for you. If you can manage interaction with your view with the target-action mechanism, it wouldn't matter.
I have an application where I did use 2 separate UIViewController subclasses below another view controller to manage a table view and a toolbar. It 'kind of' works, but I got myself into a massive pickle as a result and now realize that I should not be using UIViewController subclasses for the sub controllers because they contain behavior that I don't need and that gets in the way.
The sort of things that went wrong, tended to be:
Strange resizing of the views when coming back from sub navigation and geometry calculations being different between viewWillLoad and viewDidLoad etc.
Difficulty in handling low memory warnings when I freed the subview controllers when I shouldn't have done.
Its the expectation that UIViewController subclasses won't be used like this, and the way they handle events, using the navigation controller etc that made trying to use more than one UIViewController subclass for the same page tricky because you end up spending more time circumventing their behaviour in this context.
In my opinion, The Apple Way is to provide you the "one" solution. This served the end-users very well. No choice, no headache.
We are programmers and we want to and need to customize. However, in some cases, Apple still doesn't want us to do too many changes. For example, the height of tab bar, tool bar and nav bar, some default sizes of the UI components(table view), some default behaviors, etc.. And when designing a framework and a suite of APIs, they need to nail down some decisions. Even if it's a very good and flexible design, there is always one programmer in the world wants to do something different and find it difficult to achieve against the design.
In short, you want a table view and a label on the same screen, but they don't think so. :)
What is the best approach to implement tabs that look like web applications on the iPhone, like the screenshot below (notice the "Checkin-Info-Friends" tabs)? These are not part of the UIKit standard library, but seems to be very common lately.
I've spent considerable time developing applications for the iPhone, but not developing controls like that one. What would be the best approach here:
create a new UIView for each tab content, and add the three subviews to the mainview straight away?
create new UIViews only when the user clicks on each of the tabs?
Put all the content in a UIScrollView, and just change the page as the user clicks on each tab?
Maybe there are open source controls for this out there? I couldn't find anything.
(source: foursquaregame.com)
My approach to a similar problem was to make all 4 (in my case) tab views, but respond to didReceiveMemoryWarning by releasing all but the current tab view. (Then, of course, you must make sure that you create the new view, if it doesn't exist, when the user chooses a new tab.)
I thought this was a good compromise - a speedy reaction to the user at first (and in my case memory footprint is at its lowest at this point in my app), and then a response to low memory to avoid being shot.
I think it best just to have three UIView* references to the subviews in the parent view or view controller, all initially null, then to have subroutine to hide the other two views if they are visible and either construct and show or just show the new view. Assuming no extraordinary memory requirements.
I think with such a small screen area load/unload concerns at the subview level are unlikely to be a concern, but if the parent views need to be loaded/unloaded, the subviews should all go (be both hidden and unloaded), and on reload, loadView should call the routine described in the last paragraph at startup.
If there is in fact a great deal of memory or resource use by any of the three subviews, then my advice is reversed and each of the subviews and/or any memory-intensive objects behind them should be not only hidden but unloaded whenever possible. I think with your use of Google maps there, a need to unload when hidden might apply to that.
Is this th right point to make? Is there some extra detail I'm missing?
You can have each tab be a real view controller with nib and everything. The only catch is that you must forward on the standard view controller calls you want to receive (viewWillAppear, etc) but it makes the coding much cleaner since you code just as you would for any other view (although for a smaller space).
You call each controllers "view" property to get out the view, which you add as a subview of a container view you have under the tabs.
If all three are table views, you might get away with using a single UITableViewController that changes contents based on the selected tab. Otherwise I second KHG's comment of using real view controllers to back up each of the subviews.
For the tabs themselves consider subclassing UISegmentedControl.
I've involved myself so much in NavigationControllers that I've become kinda ignorant with other options.
Here's what I want to accomplish, I've built Subclassed ViewControllers to Push via NavigationController that works pretty fine.
However, to avoid the Idea of going back and getting to a new view doesn't fit for quick access since this is about calculator, I came up with using SegmentedControl.
I added UISegmentControl to the NavigationBar.
What I want to accomplish, is on tapping of a segment, The Calculator1ViewController Loads below the NavigationBar. And on tapping another Segment, the previous ViewController is unloaded and a different "Calculator2ViewController" is loaded.
I'm not quite sure how to do it, loadFromNib may not work too well, because I'm using custom ViewControllers.
Any suggestions would be great help.
You might be better off making it a single view controller, and just swapping out the views.