iPhone dev view swapping - iphone

So I'm trying to find out the best way to swap views for an iPhone game I'm making. I have a "root view controller" that has a reference to all the view controllers I want to swap between. So I add the main menu view to this root view controller - [self.view addSubview:mainMenuController.view]; - Then in the main menu view I have an instructions button. I define an IBAction in the mainMenuController to respond to the instructions button being clicked. From there, I call [self.view removeFromSuperview] which works great. It gets rid of the main menu. So next I want to add the instructions view. I figured that it would be as simple as [super.view addSubview:super.instructionsController.view], but no luck! I've thought of a few ways to get around this, but they all seem very inelegant, as I would like to keep all references to my view controllers in one place, the root view controller. Any thoughts?

Could you not have your main menu view controller tell the root view controller that it's closed, along with a reference to what view it should load next? I'm assuming you're not doing something akin to what UITableView does, in which case you'd likely want to use a stack.

Are you mixing super (an Objective-C keyword) with self.superview (an UIView property)?
At any rate it's indeed a better design to inform your main controller to switch to another view, rather than making that decision from the added subview.

I just got around it by setting a delegate property in each of my controllers to the root view controller.

Related

using dismissModalViewControllerAnimated without deallocating modal view controller

I'm creating an app using the iPhone Utility App framework, and I'm trying to use a navigation controller on the flipside view, as there will be a lot of drilldown options on this view. When I'm done with this view, I call the following code:
- (IBAction)done:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
}
When I dismiss this view, I want to be able to go back to the place in the navigation I was currently at when I reopen this view again. However, when I dismiss this view using this method, the vc gets deallocated, therefore the menu starts back at the beginning when I try to go back to the menu.
Thoughts?
You'll need to retain a reference to the object (I'm calling it the options controller). I would say the easiest way is to create an iVar in the presenting view controller that references the options controller. Then, when you go to present the options controller again, just present the referenced options controller rather than creating a new controller. If different view controller objects can present the options controller, you'll need to either pass that reference around, or store it in some object that all the other view controllers have access to.
Hmm not much code so maybe I'm misunderstanding your setup, but...
You could use the AppDelegate to store (as a property) your current position (index) in the views collection of the Navigation controller, and then write a method that pushes to that (stored) position when you re-visit it later.
Might be an easier way to do it though..
So what you want is to flip from a view to another view? If you want to keep the navigation bar status between flipping, I recommend you use only one view controller to control this 2 views. you can use + transitionFromView:toView:duration:options:completion: of UIView to flip views.

How does iOS know which view controller should be active?

If I want to replace one screen of an app with another, but I don't use a navbar/tabbar controller, then I could just remove oldViewController.view from window and add newViewController.view to it. That's all, now newViewController will get rotation events, etc.
But UIView does not reference "its" controller, so how is this possible, how iOS know it should make newViewController an active one? Does iOS do some magic, it internally references controller from view or what?
UPDATE:
I think I was misunderstood: I don't ask how to make some view controller an active one - I know that. I'm just curious, how is it possible that I pass some view to UIWindow object ([window addSubview:view]) and it somehow finds view controller although view doesn't know its controller.
yeh I had the same question like you. and I figured it out.
UIView is derived from UIResponder. and UIView must subclass UIResponder::nextResponder.
Its default implementation is returning a view controller of the view (if it hadn't, it would be super view)
So, consequently view can see its controller. that means window know the topmost view and also
its controller.
good luck.
Unfortunately, iOS only send events to the first ViewController of the stack. You can try and present a new one on the top of others with video for example, it will never rotate.
If you don't use navbar/tabbar controller you will have to add and remove everytime from the Window to keep only one at the time if you wand to have events.
The main UIWindow class for your application will have a view controller set in its rootViewController property. That controller's view is the "main" view for the app. This is usually setup in the main .xib for the project. That view controller will receive the usual events like "viewDidAppear" or "willRotateToInterfaceOrientation". You can put up your own view over top of it if you want to, but you will need to manage those events yourself. Usually you don't do that though. You just use a UINavigationController or UITabBarController as your rootViewController and allow them to manage getting the events to new "pushed" view controllers, or you popup view controllers with "presentModalViewController".

How do I remove a view controller from my view hierarchy?

My app has a welcome screen that can only be shown in portrait mode. After the user has tapped through the welcome screen I'd like to show another screen that can be used in both portrait mode and landscape.
I have set up a view controller that implements shouldAutorotateToInterfaceOrientation: returning YES only for UIInterfaceOrientationPortrait, and I add the view to the window with [window addSubView:view]. I tag this view with the tag 1.
When the user taps through the welcome view and the app moves on to the new view I do:
[[window viewWithTag:1] removeFromSuperView];
[window addSubView:myViewController.view];
Where myViewController is an instance of the 2nd view's view controller (that handles the shouldAutorotateToInterfceOrientation method properly).
Now when I rotate, it still calls shouldAutorotateToInterfceOrientation on the original view's view controller, and does not call it on the new view's view controller.
This note from Apple says that only one view controller will get rotation notifications; however, I have removed the other view controller.
What am I doing wrong?
actually that note doesn't say that "only one view controller will get the notifications" but instead it says that "Only the first view controller added to UIWindow will rotate.".
So this might be the problem.
To resolve it, i would say to always have a view added to your window (call it permanent), and add your welcome screen and the next views to this permanent view.
Hope this helps.
as the note you link to state:
Only the first view controller added
to UIWindow will rotate.
So put a flag that makes sure that shouldAutorotateToInterfceOrientation returns NO until the user have dismissed the screen - and then returns YES afterwards. This is a simple and working solution - however, from a code readability point it might be confusing that a "dismissed" view actually controll the rotation.
Personally; my experience is that it's not really worthwhile having some views rotating and some don't - and users tend to don't like it.
happy coding
I wrote up a quick test that shows what you are trying to do should work. Here are the basics I did:
Create two view controllers. App starts with the first view controller being set in the AppDelegate into an instance variable viewController through NIB files. It is then added to the window as you have written.
I then setup an action that when called (could be a Timer, button on first view controller, etc.) that performed the following:
Remove view using [self.viewController removeFromSuperview]. This is different than the way you have done with the tag.
Created second view controller and assigned it to self.viewController.
Added to window like you have specified.
Not sure what is incorrect with your code. I would guess that perhaps the first view wasn't really being removed.

how to keep control of my root view while loading a view controller as a subview?

I have a root view which contains a table and a button. When I press the button a view is loaded on top of the root view but keeps my root view visible. The view that appears after the button is pressed is suppose to act as a menu that is scrollable. My problem is that when I want to close the menu that appears.
Im using the [self.view removeFromSuperview] on the subview that appears on top of my root view. When the subview disappears I'm not able to make selections from my table.
How can I get rid of my subview and still keep control of my root view. Also how can I change what my root view displays based on the menu selection I have made. Since my menu is a subview of my root view.
I'm not sure if these things are possible. I have been experimenting but so far I lose control of my root view. I'm able to scroll up and down my table and relaunch the menu subview. But I cannot make any selections from the table. Also I'm unable to change what my root view displays after I have made a choice from the menu.
Please if anyone could shed some light on this issue for me I would greatly appreciate it.
Okay, I don't fully understand what you are doing, so if my answer is rubbish, please forgive my.
As far as I understand, you have a ViewController with another ViewController as a subview. If so, you might very well run into unexpected behavior, since, according to the documentation
Each custom view controller object you create is responsible for managing exactly one screen’s worth of content.
There are some exceptions (e.g. a ViewController inside a TabBarController) but a ViewController inside a ViewController is definitely not the way to go.
So, if you want to show a ViewController after your Button is pressed, show it as a Modal ViewController by using the "presentModalViewController:animated:" method of your "superview". You can make your selection in the ModalView and dismiss it via "dismissModalViewControllerAnimated:"

View controller/NIB architecture for non-navigation application with transitions?

I'm tinkering with an iPad app that (like many iPad apps) doesn't use the UINavigation root view control system, so I don't have natural ownership for each app "view". I essentially have two basic views: a document list view, and a document edit view.
I'm playing with UIView animation for getting from a selected document to the edit view.
I also have a toolbar on top that exists (with different buttons) in both "views".
Because I don't have UINavigation running the show for me, I have a tendency to just throw more and more stuff into one NIB and one view controller that owns the whole container. But now I'm trying to figure out how to segue from the document list view to the edit view if the edit view lives inside a different NIB, preserving the toolbar too.
Anyone have thoughts or experience on app structures like this? I find the docs lacking on best practices around code/UI structure for anything except trivial one-screen apps or full-on navigation apps.
You're not "supposed" to have parent/child view controllers owning subcomponents of the same "screen" according to the docs, but this implies one massive honking view controller that basically contains the whole app, and that can't be right.
Not sure if there's a "right answer" to this; I'm looking for some intelligent examples or suggestions. Nobody's touched this question in months, so I'm adding a bounty to generate good chatter. :)
Thanks!
UPDATE: I'm not talking about a split view, which is clearly well handled by a split view controller. Instead, take a look at Apple's iWork apps (e.g. Pages) which have a document list view and an independent edit view, but these are related by animation.
Maybe the real question here is: how would you (or could you even?) build a "container" view controller like the split view or navigation controller, yourself? Are you required to build the whole damn thing from scratch? I sense that you are, because seems to be hidden wiring in the interaction between view controllers. If so, thoughts on this?
I think the only hidden wiring in view controllers is setting parentViewController, which is required to support the categories declared for split and navigation.
View controllers are designed to be nested, with each controller owning a part of the view hierarchy. The only design goal is that no view controller reach into the view hierarchy of another controller. A parent view controller will usually have some call for adding child controllers so that it can set the frame of the view within the view hierarchy it owns. A child view controller should not do anything to the superview of the view it controls, as that is owned by another controller. Not should it set the center or frame of the view it controls.
For example, a navigation controller has a push method, in which it removes the previous controller view, adds the new controller view, and sets the frame of the newly added view. In general, a parent view controller is free to set the frame of the view of a child controller, but not the bounds.
If you want to change the animation of a navigation controller, I think you would start by implementing every method with an animated: argument. Set up your animation then call super with the animated flag off before committing the animation.
I haven't tried the multiple-view-controllers thing outside of the UIKit-provided ones (navigation/tab-bar/modal/etc) but I don't see why it shouldn't work. Under the hood, everything is a view, though I'll note that UIKit has special views for view controllers which no doubt have some kind of special handling by the system (UIViewController has a wrapper view, UINavigationController has a UINavigationTransitionView or something, ...).
I'd advise not worrying too much about "best practice" — just code something which does what you want. A couple of options:
Stick logic into view classes (ewwww!). One of our apps does this so it can handle rotation in a custom way (views slide in/out instead of rotating). We should've probably implemented our own view controller logic instead.
Break the model into components which correspond to views. Make each view know how to load its component and recursively load subcomponents. Then the view controller only needs to worry about "big picture" stuff.
Also note that you can load multiple nibs into the same view controller by e.g. connecting it to an outlet called editView.The big difference is that it's not done automatically by -[UIViewController loadView] so you need to do something like
-(EditView*)editView {
if (!editView) {
// Loads EditView into the outlet editView
[NSBundle loadNibNamed:#"EditView" owner:self];
}
return editView;
}
You'll also need to worry about adding it to your view hierarchy, unloading it on -(void)viewDidUnload (iPhone OS 3.0+), setting it up in -(void)viewDidLoad in case there was a memory warning during editing mode, etc...
It's not easy, but UI never is.
You need a master-detail view implemented with a split-view/popover-view and controlled with a UISplitViewController.
The master view is the document list and the detail view is the edit view. Each has its own controller. The two controllers themselves are managed by the UISplitViewController.
If you don't use the splitview controller you will just end up hand coding something that works very much like it. This is really the only way to do what you want easily in the API and it is the layout that iPad users will expect.
See Creating a Split View Interface in the iPad programming guide for details.