How do I switch ViewController instead of adding to stack? - iphone

I have a number of objects linking to each other in a circle. Each object holds a reference to it's neighbors, square and triangle are different class types:
The tow classes, triangle and square, are made visible with a ViewController, and they link to each other with segues.
So far, no problem. However, while I'm browsing around in my structure, I keep adding ViewControllers on top of each other. Not only does this seem a bad practice memory-wise, but it also presents the problem that when I want to quit this structure, I have to back-track by closing all ViewControllers that I opened.
So what I'm looking for, is a way to not add the next ViewController on top of the current on in the stack, but to replace the current ViewController with the next one.
I've been looking for a while for a solution, but have little success. So I feel that doing what I want is either impossible, or I'm just not getting an obvious point and don't know what to look for. Do I need a RootViewController for something like this? Or should I create a custom segue that dismisses the old ViewController before adding the new one? I'm really at a loss here.

Add all subView once , in viewDidLoad and give tags to all you SubView after that where you you want to show that view in viewController don't add it just bring it to front by calling the function [[self.view viewWithTag:1]bringToFront]

Since you are probably using a navigationcontroller, you should have a look at the UINavigationController reference. There are methods to modify the navigation stack. You cannot do this only with a storyboard. You will need some custom code.

You should have a look at the UINavigationController method setViewControllers:animated:.

Sounds like you want to do one of a couple things
Replace your rootViewController
Have a rootViewController which acts as a container for a single UIViewController and change that out as needed. In iOS 5 you can do this with a custom UIViewController, but or you could use one which Apple provided.UINavigationController` can do it, but unless you are also using it to navigate a tree like structure of view controllers it's probably not the best option.
Your best answer sort of relies on your need.
If your controllers don't have much state or don't get swapped in and out a lot you could use option 1.
If you expect users to swap between controllers often and quickly and/or your controllers require significant setup or have a lot of state then you might want to a NSArray and just use presentViewController:animated:completion: to show different controllers when needed. Storing your controllers in a NSArray has the added bonus of easily being able to identify their neighbors.

The UINavigation controler's method setViewControllers is an option.
Another would be to pop the most rencent view controller using popViewControllerAnimated:
In some cases popToRootViewControllerAnimated: would be best or even popToViewController:animated:. Hoever, I personally was not successful using popToViewController:animated: but that may have been my fault at that time.
Yes, I think you need a root view controller. I myself tried to exchange the root view controller the other day but failed doing so. In the end it was probably not the most elegant solution but easier for me to implement some dummy root view controller which does nothting but display my app logo in the background (Same as the default image but moved into negative coordinates in order to match the default image on startup. It is laying 'behind' the navigation bar and status bar.). It could show some empty black background or so. In the end it is will most probably never be visible.

Related

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.

Must a view controller always have a delegate in iPhone apps?

I'm learning how to develop my own iPhone apps but I'm having a tough time understanding certain concepts.
First, am i right to say that for every view, there must be a view controller for it? And for every view controller, must there be a delegate for it?
Also, what is the role of mainWindow.nib? Most of the tutorials that i've read don't seem to touch that nib at all. What always happens is the setting up of a NavigationController as the root controller, which pushes another ViewController onto the stack and this ViewController will have another nib associated with it.
So can i assume that i can safely ignore the main window nib?
It's all about MVC (Model View Controller), innit?
The Model, well that's up to you - what does your app do? Think of it as the backend, the engine of your app, free of the cruft of font size decisions and touch events.
The View, Apple pretty much wrote that for you. You use their Textfields and tables and imageViews. You assemble them together using Interface Builder into your GUI (packaged as a .nib). You rarely, if ever need to subclass the standard view elements (in a game you want a custom View to draw to, as all your drawing is probably custom). You can break different parts of your GUI into different .nib files if this helps you manage them. It's entirely up to you.
The Controller, so you have probably got some work todo to enable your GUI to represent your model. You need Some Controllers. How many? However many is manageable by you. If you had a view containing 2 subviews would they each need a view controller? Nah, probably not. How complicated is your code to hook up the view to the model?
Some GUI patterns are so common that Apple even wrote the Controller code for you. EG the controller for a UINavigationBar, UINavigationController. So, if your app has hierarchical views that you need to navigate around and you need to display a navigation bar you can use an instance of UINavigationController instead of writing your own class. Yay!
Surely tho, the UINavigationController code (or any other viewController) can't magically know how to integrate with our model, with our view, can it? NO, it can't. In general in Cocoa if there is some class of object that mostly works off the shelf but also has optionally configurable behavoir - allowing us to tailor it to our needs - it is done by Delegation. ie Instead of subclassing UINavigationController we tell the specific instance of it where to find (for want of a better term) it's custom behavoir.
Why? Let's say you have a navigationController, a tableView and a textfield. UINavigationController mostly take care of your navigation needs but you have to have a crazy QUACK sound play each time the user moves to a new view. UITableView is mostly exactly everything you need from a table, EXCEPT you really want the third row in the table on the front page be twice the height of the other rows. And the standard, off -the-shelf UITextField pretty much takes care of your textfield needs EXCEPT you need your textfield to only be editable when the user is facing North. One way to handle this would be to create 3 new classes, a custom UINavigationController, a custom tableView and a custom textfield, and to use these instead. With delegation we could use the classes as they are and have one object be the delegate of all 3 instances - much cleaner.
Delegation is mostly optional, the docs will tell you when, and it's down to you and whether you need that custom behavoir.

TabBar Controller question

I have an app that has four tabbar controllers views in it. When the app starts up, all four are loaded via SQL select statements. How do I tell it not to load these controllers at startup, but to do it when I select a value from the first screen?
thx
wes
I'm assuming you have 4 ViewController placed into a single TabBarController. If this is the case, why do you want to defer loading? The actual views (usually the 'heavy' part of the ViewController) are not loaded until you actually select one in the tab bar to bring it forward (which is, I think, the behavior you're looking for).
The whole point of the UIViewController class (well, one of the points, anyway) is to allow you to place your view in a hierarchy without having to create all the UI elements required until it's actually time to show it. This makes app organizations much easier.
make simple UIViewController in tabbar, but when tab is selected make loading

Why shouldn't a UITableViewController manage part of a window in Cocoa Touch?

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. :)

Using Segment Controller to "Push" rather than UINavigationController

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.