remove 2 subviews in one go - iphone

I am trying to remove two viewcontrollers (that have been added on top of each other) with one method. I have made the views in interfacebuilder. they all have their own .h and .m files to go with it.
Scenario I am in:
I have a main menu which has the view2 header file imported.
In a method I add the second view on top of the superview like so
view2ViewController * view2 = [[view2ViewController alloc] initWithNibName:#"view2ViewController" bundle:nil];
[self.view addSubview:view2.view];
then in view 2 I have added the view 3 header file so i can add view 3 as a subview ontop of view2. i have another method which is connected again to interface builder to a UIButton so upon button press a method gets called in view2 which adds view 3 on top in exactly the same way like so:
view3ViewController * view3 = [[view3ViewController alloc] initWithNibName:#"view3ViewController" bundle:nil];
[self.view addSubview:view3.view];
What im trying to solve:
I have a button in view 3 which should remove view 3.... and then it should also remove view 2 aswell so the main screen is visible.
How can this be achieved?
What I have so far:
[self.view removeFromSuperview];
This however only removes View 3... but leaves view 2 in place.
What needs to be modified so that i can remove view 2 as well??
Any help is appreciated.

I would normally do this as adding view2 and view3 as subviews of the main view. Then when the button actions are triggered, the adding and removing of subviews will be executed by the main view's view controller.
For a quick hack, I think you can try this in your button handler.
[self.view removeFromSuperview];
[self.view.superview removeFromSuperview];
Though I'm not sure if you should be doing it. :P

Is this what you need?
[[[self.view subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];

I don't know what you're trying to do exactly, but I get the impression that pushing a new view controller is what you want. If you have a UINavigationController in your app, you'd just have to do a
[navigationController pushViewController:view2 aimated:YES]
To go back to the main menu when the button is pressed, you should define a delegate protocol that looks something like this::
#protocol View3ViewControllerDelegate
- (void)view3ControllerBackToMainMenuButtonPressed:(View3ViewController*)controller;
#end
This protocol is then implemented by the class that actually pushes the other view controllers. In the implementation, you'd pop all view controllers you don't want to be displayed anymore. To do this, you could use
[navigationController popToViewController:myMainMenuViewController animated:YES]
or if your main menu view controller is actually the root view controller:
[navigationController [navigationController popToRootViewControllerAnimated:YES]
That way only one class is responsible for pushing and popping all view controllers and handling that "Back to Main Menu" button. Using a custom protocol as described above is the recommended way to handle the popping of pushed view controllers in a scenario like this.
Hope that helps!

Related

iOS: confused about removeFromSuperview and switching views

New to iPhone development, but I've been given a big project as a first go and I'm a bit stuck.
Basically the app will start with a settings screen, then you click a button to go to a dashboard with multiple option buttons. Each button will lead to a different Navigation View with tables.
The way I've approached this is to start with a UIViewController with a button, which I've got wired up but when you hit the button and I do:
[self.view removeFromSuperview];
UIViewController *newView = [[UIViewController alloc] initWithNibName:#"Dashboard" bundle:nil];
[self.view addSubview:newView.view];
the second view isn't loading. I just get a blank screen. Do I need to make a reference in the first controller to the second?
Also, am I approaching this in the right way? As long as I removeFromSuperview will I be able to load the navigation controllers on the press of a button?
Sorry if this isn't too clear, I've been through books and lots of websites but don't seem to be able to get my head around this.
Thanks
There is nothing here with the new view, rather the problem is with current view. You have removed the self.view from super view.
[self.view removeFromSuperview];
So anything added to self.view will not be shown, as self.view itself is removed.
When presenting child controller/view from a parent controller, you should consider using presentViewController. Eventually, use dismissViewControllerAnimated when you want child to disappear and parent to reappear.
In parent view controller:
ChildViewController * child = [[ChildViewController alloc] init];
[self presentViewController:child animation:YES completion:Nil];
In child view controller, ie. in some action handler:
-(IBAction)close:(id)sender
{
[self dismissViewControllerAnimated:YES completion:Nil];
}
IMHO you should also get in the habit of naming instance variables to what they are instantiated from. In your example you name the instance newView, when it should be something like newViewController. That way you make sure you don't mix up views with view controllers.
[self.view removeFromSuperview];
You've removed the view from the superview
[self.view addSubview:newView.view];
But you're adding the new view to the same view that you have just removed from the superview. It's not displaying anywhere.
Your third line adds newView as a subview of self.view, but you just removed self.view from it's superview.
I'd suggest reading more about view controllers. You'll want to have one view controller per "screen", so one for your settings screen, one for your dashboard, one for each table, and so on. Then, manage which one is visible by pushing and popping these view controllers from the nav controller's stack.
This removes self.view, which will most likely destroy the object since there will be no other references to it:
[self.view removeFromSuperview];
Here you are creating an UIViewController, and adding it's view to self.view, which is probably not what you want:
UIViewController *newView = [[UIViewController alloc] initWithNibName:#"Dashboard" bundle:nil];
[self.view addSubview:newView.view];
Look into UINavigationController so that you can easily swap screens in and out with some built in animations. Here's a bit more about them. Here's a tutorial.
The UIViewController's view should not be removed from or added to a view hierarchy outside the control of the view controller. While you might be able to get that manipulation to work now it won't in the future.
Read up on view controllers here.
The basic idea is that you present the view controller then it will take care of manipulating the view hierarchy for you.
So a better approach to get started would be to do something like this;
[viewController1 presentModalViewController:viewController2 animated:YES];
This line of code will present viewController2 with the default modal animation (slide in from the bottom). If you'd like a different animation you can change the modalPresentationStyle to one of the constants in the UIModalPresentationStyle enum on viewController1 (note thats a viewController1, not viewController2).
If you want something more like the Clock app look into the tab bar controller. If you want something more like the Mail app look into the navigation controller.

Remove current view from superview

Let's say I have a viewcontroller "ViewBViewController". In that viewcontroller I create an instance of the "ViewAViewController" and use the addSubView: method to display this ViewAViewController. It then processes a bunch of information, and is now done. I want it to automatically get removed as a subview when it's done.
I was looking at the removeFromSuperview method, but can't seem to call that from within the viewcontroller whose view I'm trying to remove (my first instinct was [self.view removeFromSuperview], but that gets rid of the entire view, not just the subview I'm after).
The only way I can think of is setting up a delegate protocol, and have View B take care of the unloading of View A on behalf of View A as its delegate. However this approach seems a bit overkill. Am I missing an easier solution?
Thanks in advance!
UIViewController does not respond to removeFromSuperview, because a UIViewController is not a UIView but a UIViewController. No surprises there. You can call removeSuperview on any view, such as the view associated to a view controller (here self):
[self.view removeFromSuperview];
or if you just want to remove one subview:
[mySubview removeFromSuperview];
or if your subview is a member of self (i.e. declared in the interface say):
[self.mySubview removeFromSuperview];
Have you tried: setHidden: YES ?
There are two basically correct solutions here:
Use a navigation controller. You can hide the navigation bar if you don't want it to be part of your interface. Then you can dispose of the top view controller and its view from either view controller by calling
// argument can be YES or NO, as you like
[self.navigationController popViewControllerAnimated:YES];
Use a delegate call that tells the parent view controller to do something like
-(void)removeViewA {
// remove the view from the view hierarchy
[self.viewAController.view removeFromSuperview];
// dispose of the view controller so it doesn't leak.
self.viewAController = nil;
}
It's important to make sure that you don't leak the child view controller and its view.
Either of these approaches works, but using a navigation controller seems more idiomatic to me.

Switching between 2 Views in 2 distinct View Controllers

I have a problem with transitioning between views in different ViewControllers.
Here is the situation:
My App is a TabBarApplication done with IB which contains a UIViewController for each Tab. The UIViewController (PlayerTabViewController) of the first tab contains another UIViewController (PlayerCreationViewController) to manage a view that will be added as subview.
I was able to add the subview using
[self.view addSubview:playerCreationViewController.view];
In the PlayerTabViewController.
The problem is that from the subview I have to return to the parent view and reload it because it contains a tableview that must be refreshed.
Using [self.view removeFromSuperview]; in the PlayerCreationViewController I can switch back to the parent view, but I'm not able to reload the tableview or do other actions.
I tried to implement the -(void)willRemoveSubview:(UIView *)subview method in PlayerTabViewController but it seems the function is never called.
Do you have an Idea of what am I doing wrong?
you are using wrong method to go on next view. just use navigation view controller to switch from one view to another view.
create a object of view
PlayerCreationViewController *playerViewController = [[PlayerCreationViewController alloc] initWithNibName:#"PlayerCreationViewController" bundle:nil];
[self.navigationController pushViewController:playerViewController animated:YES];
[playerViewController release];

adding navigation effect to view based application?

I have created View based application, here i need to navigate between views when button pressed.
so in first view controller i have created action for button pressed.
-(IBAction)loadSecondView:(id)sender
{
SecondView *sView = [[SecondView alloc]initWithNibName:#"SecondView" bundle:nil];
[self.navigationController pushViewController:sView animated:YES];
[sView release];
}
this code is not working, anything i am missing,
i can do this by [self.view addSubview:sView]; but i need navigation effect.
Thanks in advance.
You can't just hook a UIView instance to a navigation controller, that's not how they work.
Take a look at the "Navigation-based Application" template in Xcode, to learn how navigation controllers work.
You can use view controllers while hiding the navigation bar:
[[self navigationController] setNavigationBarHidden:YES animated:NO];
You can then map UIButton instances to selectors that push or pop view controllers, while keeping the navigation bar hidden.
These button instances are subviews of the view controller's view property.
Hiding the navigation bar can help provide the illusion that you are not using a navigation controller, while giving you all the functionality of the navigation controller.
Alex is right, if you create just a "View Based Application" project, no UINavigationController was created so when you push something on it nothing happen, that's normal.
You have to create a UINavigationController and make you main view its rootViewController, then you can push on it a new viewController.
I have got a solution for this,
In View based application the appdelegate file creates object for, view controller and added that view to main window, to do our task, delete the controller in mainwindow.xib and add a UINavigation controller,and create a object to it, and connect outlet to it,and then add this navigation controller view as a sub view,
its work fine.

What causes a UIViewController to become active?

I am sure this is an easy question, but one that has escaped me for some time now.
Say I have a UIViewController, either defined as a root in an XIB or on a stack. At some point in my code I want to replace it with another view controller. Just flat out replace it. How would I do that?
I have tried defining the controller and assigning, but not sure what actually makes it push on the screen with the absence of a navigation controller.
I think when you say that you want to replace the view controller, what you actually mean is that you want to replace the view. Bear in mind that view controllers aren't visible, but every view controller maps to a view, which can become visible by getting added as a subview of a visible view.
Your solution of replacing self.view with the new view controller's view may work in your particular case, but it's probably not the "correct" answer to your question. There are going to be cases where this solution won't work for you.
Let's say you have a simple view based application with no navigation controller and no tab bar controller. In your app delegate you construct an instance of YourFirstViewController, and you call [window addSubview:yourFirstController];. Your view hierarchy now consists of a UIWindow with a single subview -- the view for YourFirstViewController.
Now let's say the user presses a button on that view, which is handled by an IBAction defined in YourFirstViewController. You want to respond by "replacing" YourFirstViewController's view with a view associated with YourSecondViewController. I put "replacing" in quotes because we more commonly present a view by pushing its view controller onto a navigation stack, or calling presentModalViewController:animated: to present the view modally, but let's assume that you've rejected those options for some reason, and you actually do want to manually replace YourFirstViewController's view with YourSecondViewController's view.
This is a simple matter of manipulating the view hierarchy. You want to remove YourFirstViewController's view from its superview (the UIWindow in this case), and you want to add YourSecondViewController's view as a subview to replace it. Your action would therefore look something like this:
- (IBAction)replaceButtonClicked {
UIView *mySuperview = self.view.superview;
YourSecondViewController *secondController = [[YourSecondViewController alloc] init];
[mySuperview addSubview:secondController.view];
[self.view removeFromSuperview];
[secondController release];
}
When we use a methods like -pushViewController:animated: or -presentModalViewController, the receiving controller manipulates the view hierarchy for us. This may make it seem like we're looking at view controllers on the screen, but we're not. We're just looking at a big hierarchy of nested views going all the way up to a UIWindow at the top.
You can present a new view controller modally:
[self presentModalViewController:aViewController animated:YES];
This won't outright replace the current VC, but it will display a new view over the current view.