There's code below, but this is also a conceptual issue. The question: Are the methods below the right way to move through view controllers? And that's broad, so let me add some specific details.
Say you're in View A. This view presents options to go to View B or View C. After the user makes the choice (i) I want to load the new view and (ii) the user won't be going back to View A. (Also, btw, View A was my initial rootViewController.)
So, say I wire up two buttons in View A, each to load its respective view. Is this an efficient/solid way to do it:
- (IBAction)loadViewB:(id)sender
{
ViewBController *viewBController = [[ViewBController alloc] initWithNibName:Nil bundle:Nil];
[self.view.superview insertSubview:viewBController.view atIndex:0];
[self.view removeFromSuperview];
}
- (IBAction)loadViewC:(id)sender
{
ViewCController *viewCController = [[ViewCController alloc] initWithNibName:Nil bundle:Nil];
[self.view.superview insertSubview:viewCController.view atIndex:0];
[self.view removeFromSuperview];
}
The "insertSubview:atIndex:" method seems to be right, based on Apple's View Controller Programming Guide. Also, the code works. But should I call the "removeFromSuperview"? Or should I just stack them up? (And if anyone has comments about memory management, I'm all ears.)
Also:
I don't want to move through structured data. So, it doesn't seem like using a UINavigationController would be right.
I don't want to temporarily interrupt flow. So, strike a modal view.
I know it's a simple question, but I just want to make sure I've understood the documentation right and have grasped the concept generally.
Thanks ahead of time.
I don't think there's anything wrong with your approach. Just beware that simply [self.view removeFromSuperview] might not cause any memory to be freed up, for example if your app delegate holds a reference to your root view controller. It might be a good idea to give this view-switching responsibility to the app delegate, so it can choose to release the reference to the root view controller if it desires.
Related
I have MainVC than contains 2 tabs: FirstVC and SecondVC.
Then I tap on some of this taps I want to present below desired View/VC.
I am working on this project with Nib, so I have some confusion about it.
That object should I use here? View? How?
How I have MainVC with 2 View that hidden/shown based on tab.
In FirstVC I need to load tableView. In SecondVC - simpleView
So, can somebody give me some advices how to achieve this thing more cleverly?
You might want to use Container View Controllers, I blogged about that awhile back. (See http://www.notthepainter.com/container-view-controllers/)
Text pasted here for the future:
OS5 added something a lot of iOS developers have been needing, container view controllers. This lets you put a view controller inside another view controller. This is wonderful for countless reasons, but the one that draws me is reuse and abstraction.
I was working on a app which had 2 similar windows, they had a top part (body) and a footer. The top part was easy, they each had their own UIViewControllers. But when I went to add the footer to the second one I got to thinking DRY, I was repeating myself and that’s never a good idea. So I abstracted out a parent class and I went to put the footer code in and I got stuck, I wanted my footers to also be view controllers.
I remembered a talk I attended about new iOS5 features and container view controllers was mentioned. After a bit of googling around I had it.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// set up the footer contained view, this has nothing to do with table footers, this is below
// the tableview
//
FooterViewController *vc = [[FooterViewController alloc] initWithNibName:#"FooterViewController" bundle:nil];
vc.view.frame = self.footerFPOView.frame;
vc.delegate = self;
[self addChildViewController:vc];
[vc didMoveToParentViewController:self];
[self.view addSubview: vc.view];
}
Of course there are a few things to note. First, hooray, I’m loading my footer from a xib file. I’ve placed a UIVIew called footerFPOView in the outer view controller’s xib, this is a trick I use all the time. FPO stands for For Position Only and that lets me use interface builder for positioning. I communicate with a protocol, hence the delegate. And then I call addChildViewController to add it, and then I tell the new one that it has a new parent, and finally, add its view.
This is just a few lines of code yet the window should respond to both view controllers and respond to rotations.
I am interested in creating an app that starts with a menu which may possibly contain an options view, then steps from the menu view to a data-item selection view, then to a configuration view, and finally a result view that displays progress or changes. I want to have this process be repeatable like a loop, and have the user be able to jump backwards to a previous view if necessary. Jumping from view to view would of course be a user input / output with a button or something. FYI, I am using Xcode 5.1.1.
What would be the best approach to this? What kind of view controller is going to do the trick? I have heard a lot about navigation controllers, tables, etc.. but am having a hard time figuring out what to use in my case.
Below is a state-diagram similar to what I would like to do...
A UINavigationController should work great as your root view controller. It automatically includes a back button, and you can use the popToRootViewController method to return to the root of the navigation controller. You can set up a navigation controller as your root view controller from the applicationDidFinishLaunching method using this code.
MainMenuViewController *mainMenuViewController = [[MainMenuViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:mainMenuViewController;
self.window.rootViewController = navController;
For more information take a look at apples UINavigationController programming guide https://developer.apple.com/library/ios/documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html
Each of your other screens may use different types of view controllers depending on their specific needs. If you need to display a list of items, definitely look into a UITableView. Apple's documentation for a UITableViewController can be found here https://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewController_Class/Reference/Reference.html
I'm trying to make a custom tab bar controller by creating a view controller, then add buttons at the bottom of the screen. In this VC, I'll have reference to 4 other view controllers and switching them around when user click on the buttons. I'm not sure if this approach is causing any problem compare to using UITabBarController.
I need to do it this way because the middle tab button will have a 3D object in it, and I think I can't do this with default UITabBarController.
What I'm thinking is that this approach would lead to out of memory issue because I keep too many objects (4 view controllers) alive in memory, and each view controller has lots of image & animation in it. Not sure if this is the same as UITabBarController or Apple has some good way to deal with memory management here.
Please help!
Thanks.
In general I think you are over-optimizing too early if this isn't even a visible problem yet. If you implement your container properly using UIViewController Containment (A good guide here), you shouldn't have any memory issues.
Examples from that writeup:
When you are adding a child view controller (switching to a "tab"), you would do something like:
UIViewController *newTabViewController = [UIViewController new];
[self addChildViewController:newTabViewController];
[self.view addSubview:newTabViewController.view];
[newTabViewController didMoveToParentViewController:self];
Then when you are transitioning FROM a tab, along with the above code to go to a new tab, you would do:
[oldTabViewController willMoveToParentViewController:nil];
[oldTabViewController.view removeFromSuperview];
[oldTabViewController removeFromParentViewController];
Using the containment APIs will call all of the appropriate view lifecycle methods on the viewcontrollers being transitioned (viewWillAppear: viewDidAppear: viewWillDisappear: viewDidDisappear:)
In order to make your individual tabs more memory efficient, just make sure to do any appropriate clean-up in viewDidDisappear: which you can then rebuild in viewDidAppear:.
That said, this is unlikely to be an issue unless perhaps your individual viewcontrollers are keeping very large images in memory or something like that. You have to keep in mind that all existing containers also keep all of their viewcontrollers in memory without issue.
I am working with the project of ios and doing well in it. But now i stuck at one place where i am having three views (Say 1stview, 2ndview, 3rdview). I am navigating to second view from first view and third view using the code line below.
[self.navigationController pushViewController:first view animated:YES];
How can i check on second view wheather i am navigating from first view or third view. So that i can use particular condition on it.
So please help me out regarding this issue. Your help will be much appreciable.
Take a variable in second View controller. When you are creating the object of it, set proper value into it. Later on when it will get pushed, you can use that value to take proper decisions.
In the file of FirstViewController you will write below lines:
SecondController *controller = [[SecondController alloc]init];
controller.flag = 1; //That means you came here from viecontroller 1
[self.navigationController pushViewController:controller animated:YES];
In the file of ThirdViewcontroller you will write below lines:
SecondController *controller = [[SecondController alloc]init];
controller.flag = 3; //That means you came here from viecontroller 3
[self.navigationController pushViewController:controller animated:YES];
Try to arrange thing so that the 2ndView doesn't know about 1stView or 3rdView, but instead just changes it's behavior according to how it was configured. So, let's say that when you're navigating to 2ndView from 1stView, 2nd should display with a green background and when you get there from 3rd it should use blue instead. Rather than telling 2nd which controller preceded it, have the preceding controller just tell 2nd what background color to use. Same goes for any other aspect of 2ndView's behavior.
The benefit of doing it this way is that you can change 1st or 3rd without having to change anything in 2nd, and you can later add a 4thView or 5thView that also use 2ndView without having to change 2ndView.
Implement the method – navigationController:willShowViewController:animated: from the UINavigationControllerDelegate Protocol Reference. Inside this method you can check the navigation stack to get the current view controller using several properties of UINavigationController. An example would be access the visibleViewController property.
As #Apurv pointed out you need some sort of identifier mechanism to be able to know which view controller the call came from. e.g.: viewController.view.tag
Can anyone tell me what the best way to do the following is in Xcode (iPhone).
I have a main navigation screen with some buttons on it. When the user clicks any of the buttons they are taken to a sub-navigation screen with more option buttons on it. Here they click whichever button and are taken to a list of options. Clicking on any list option will display a screen with some information to the user. Each one of these screen ( no matter what section of the app you're in) will look the same. Only text and images on these screens will change.
I have enclosed a diagram that might explain it better. What is the best way to handle this in Xcode? I have tried doing it all in Stroyboard as I'm new to Objective C but just the sheer amount of individual pages is slowing my machine down to a crawl. So a rethink is required.
I am also doing an Android version of this app and I'm using Fragments for this. Can anyone please help?
EDIT: Just got to my devel machine and this is what I have been doing so far. I realise now this is the complete wrong way to do it. I have created a view controller for each "screen" if you like.
So I just create one view controller for all "screen" of e.g. Individual Page as per diagram and then add the text dynamically depending on what screen is selected? Can anyone point me in the direction of a tutorial or what I need to be searching for? I have no idea where to start with this using Xcode.
If the elements of the view are the same (and only the actual text and images are changing), all you need to do in your storyboard is to create one view controller that will have all these ui elements, from code you can then set it up depending on the content that you want to display in it (depending on what the user clicked in the previous view controller).
EDIT:
Not sure why it was downvoted, but i'll be more clear. Clearly that one view controller is not ALL you need to do in the storyboard. It's all you need to do ON the storyboard related to all the elements called Page in the diagram. Then you would have to link it to a PageViewController class and to all the outlets related to configurable UI elements and in the code of your prepareForSegue: method from the Secondary Nav Screen View Controller you would have to configure it accordingly to what you want to show.
Here you can find a good beginner's tutorial, along with many other good tutorials. What you're probably missing is that you also need to tell the storyboard what class the view controller is and how to connect stuff like labels and imageviews to the actual code so that you can configure them appropriately.
I.E.
From what you're describing, it sounds like you want a UINavigationController as your app's window's rootViewController and to show your screens inside that. You want to create four controller classes:
HMMainScreenController
HMSecondaryScreenController
HMListScreenController
HMPageController
Hopefully it's obvious what would be in each. You'd set up your window in your app delegate like this:
HMMainScreenController *mainController = [[HMMainScreenController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:mainController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
When the user taps a button in your main controller, you'd do this:
HMSecondaryScreenController *secondaryController = [[HMSecondaryScreenController alloc] init];
// configure it appropriately
[self.navigationController pushViewController:secondaryController];
and so on for your list and page controllers.