I have an application with multiple views. I can click on different buttons to select different views, one of which displays a table. When I select a cell on that row, I want to display a new view. I see a log line indicating that view was loaded, but the screen doesn't change.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *targetCustomCell = (UITableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"in didSelectRowAtIndexPath");
ItemDetailsViewController *detailsController = [[ItemDetailsViewController alloc] initWithNibName:#"ItemDetailsView" bundle:nil];
[self.navigationController pushViewController:detailsController animated:YES];
[self.window addSubview:[detailsController view]];
[detailsController release];
detailsController = nil;
}
In the ItemDetailsViewController, I have
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"in ItemDetailsViewController.viewDidLoad ");
}
I see both log lines, but the screen doesn't change. Why isn't the view changing? Is there some other way to change the view?
What happens if you try to present your details controller using [self presentModalViewController: detailsController animated:YES] instead of the navigation controller's pushViewController? Also, adding the view to the window shouldn't be necessary. Pushing the view controller should be sufficient.
Try adding NSLog([self.navigationController description]) and see if self.navigationController is nil. (Might happen if your current controller isn't a sub-controller of a UINavigationController). Passing a message to a nil object just silently fails, so there's a good chance that's the problem.
Hope that helps!
EDIT: It's usually not necessary to subclass UINavigationController. Check out this page in Apple's docs: Apple Docs: Using Navigation Controllers It explains the setup pretty well. If you're creating your "root" view controller programatically in your application delegate, you'd want to do something like this:
// set up main view controller
DrawingBrowserController *controller = [[DrawingBrowserController alloc] init];
// create a navigation controller that "wraps" the controller
navigationController = [[UINavigationController alloc] initWithRootViewController: controller];
[controller release];
// Add the navigation controller's view to the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
Basically, you're "wrapping" your root view controller in a navigation controller. If you're using Interface Builder, you can also set things up there.
Did you make sure your navigation controller is the root view of your window?
You usually should do it like this in the applicationDidFinishLaunching method:
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
Additionally, you should remove [self.window addSubview:[detailsController view]];, as it is not necessary.
Related
I am having an app which has a UITableViewController which is my settings page. I am pushing the UITableViewController with a presentModalViewController using self.navigationController (using storyboard ID). however each time I try to see that page, it's showing exception. After reading few posts I tried implementing two methods
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [super tableView:tableView
cellForRowAtIndexPath:indexPath];
return cell;
}
**my .h File**
#interface Setting : UITableViewController<UITableViewDelegate,UITableViewDataSource>
I have done all UI settings in IB so I didn't change anything in above two implemented methods.
In mainviewcontroller from where I am pushing the view to UITableViewController, I am using the below code
Setting *nextController = [[self storyboard] instantiateViewControllerWithIdentifier:#"setting"];
[self presentModalViewController:nextController animated:YES];
Setting *dvc = [[Setting alloc] init];
[self.navigationController pushViewController:dvc animated:YES];
As I already set all UIs in IB why do I need to implement those methods? At least I can seen the view correctly.
It looks like you're trying to initialize the same viewController twice. You don't need to alloc] init] after you instantiateViewControllerWithIdentifier. At least, from my experience you don't. Try this:
Setting *nextController = [[self storyboard] instantiateViewControllerWithIdentifier:#"setting"];
[self.navigationController pushViewController:nextController animated:YES];
That will "push" the nextController with the storyBoardID of "setting" from the right into your existing NavigationController.
However, using my intuition, I believe you want to present a settings view modally, that has it's own NavigationController. In that case, try this code, which wraps the Settings ViewController into a NavigationController, and presents that whole thing modally, so you can navigate within settings:
Setting *nextController = [self.storyboard instantiateViewControllerWithIdentifier:#"setting"];
UINavigationController *navcont = [[UINavigationController alloc] initWithRootViewController:nextController];
navcont.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:navcont animated:YES completion:nil];
Alternatively, you could do all of this in the Storyboard itself. Select your settings view controller, and go to Editor Menu > Embed In... > Navigation Controller. Then make a segue from your button to the navigation controller that holds the settings controller. Set the segue to "Modal" and you're all done.
I have a ViewBased App. I added a UITableView on one of the UIViewControllers. It shows the data and I implemented all the delegate methods etc. My problem is when I want to show the detailView it just doesn't happen. My code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *detailViewController =[[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
NSLog(#"DidSelectRowAtIndexPath");
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
I see that I need a navigationController but I don't have one and I was unsucessful trying to add one programatically. I don't have one in my appDelegate either, so my question is do I need to add one to show the detail view? If yes, please give me a code sample how to do that.
If not, what other way is there?
I am new to iOS so I am a bit lost here.
Please help!
To add a navigation controller programmatically just for this detail view, you need to something like this:
UINavigationController * controller = [[UINavigationController alloc] initWithRootViewController:detailViewController];
[[detailViewController] release];
[self presentModalViewController: controller animated: YES];
If you want to use pushViewController, you need to already have a navigation controller surrounding the view you're starting with.
You need to add the Navigation Controller FIRST, then your master table becomes the root view controller of the nav controller, then when you tap a row in the table, you push another view controller onto the nav stack.
How does your master table get into the app in the first place? If you're using a nib, it's super easy to just change out the view controller for a nav controller with the old view controller added as a child of the nav controller.
You can create one programmatically by working within your app delegate's application:didFinishLaunchingWithOptions: method like so:
UITableViewController *tableViewController = [[[WhateverYourSubclassVCIsCalled alloc] init] autorelease];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:tableViewController];
window.rootViewController = navController;
[window makeKeyAndVisible];
When I push cancel button in the third view, I want to go back to the first view directly.
I also want to remove the second view.
How can I do that?
This is the code.
// this part is in the first view.
self.second = [SecondController alloc] init];
[self.view addSubview:second.view];
// this part is in the second view.
ThirdController *thirdController = [[ThirdController alloc] initWithStyle:UITableViewStyleGrouped];
self.navigationController = [UINavigationController alloc] initWithRootViewController:thirdController];
[self.view addSubview:navigationController.view];
// this part is in the third view.
- (void)cancel {
[self.view removeFromSuperview]; // this only goes to the second view.
}
EDIT:
Can I use popToViewController in called contoller? My app crashes.
I thought popToViewController can be used only in calling controller.
And popToViewController is used when it was pushed.
I did add not push.
[self.navigationController popToViewController:[[self.navigationController viewControllers] objectAtIndex:0] animated:YES];
popToViewController:animated: is a UINavigationController method that you use when popping view controllers off the navigation controller stack. It doesn't fit for this scenario.
This user is adding subviews, not pushing them on a navigation controller stack.
As a note, it appears as a matter of design you should be using a navigation controller with the first view as the root controller, then the second pushed on the stack, and the third pushed on the stack. Then all you have to do is [self.navigationController popToRootViewControllerAnimated:YES].
I think this will work if you want to keep your current architecture:
// this part is in the third view.
- (void)cancel {
// remove the second view (self.view.superview) from the first view
[self.view.superview removeFromSuperView];
// can't recall, possibly you still need to remove the third view, but i think removing the superview will do it.
// [self.view removeFromSuperView];
}
If you prefer to try the UINavigationController route, then the easiest path is to create a new project in Xcode and select the type for a Navigation-Based Application or a Master-Detail Application. This will create a UINavigationController in a nib and add it to your window. You can then set the root view controller in Interface Builder to your FirstViewController class.
If you prefer to create the UINavigationController in code, then that is also possible. I show that below, along with the rest of the code you need, regardless of whether you create your UINavigationController in a nib in IB or in code.
I also recommend reading the View Controller Programming Guide for iOS.
In your app delegate or some other code:
-(void)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions [
// I would recommend setting up the UINavigationController and FirstViewController as IBOutlets in your nib, but it can be done in code.
FirstViewController* fvc = [[FirstViewController alloc] initWithNibName:#"FirstView" bundle:nil];
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:fvc];
[window addSubView:navController.view];
[window makeKeyAndVisible];
[fvc release];
[navController release];
}
In the first view controller:
SecondViewController* svc = [[SecondViewController alloc] initWithNibName:#"SecondView" bundle:nil];
[self.navigationController pushViewController:svc animated:YES];
[svc release];
In the second view controller:
ThirdViewController* tvc = [[ThirdViewController alloc] initWithNibName:#"ThirdView" bundle:nil];
[self.navigationController pushViewController:tvc animated:YES];
[tvc release];
In the third view controller:
-(void)cancel {
// returns to the first view controller
[self.navigationController popToRootViewControllerAnimated:YES];
}
Use
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
to go back to a specific view controller.
Try this:
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
This will pop to the view at index 1. Hope that Helps!
// this part is in the third view.
- (void)cancel {
self.first = [SecondController alloc] init];
[self.view addSubview:second.view];
}
And I think if you have you don't need to be worried about removing beneath view, later these will removed.
I'm currently trying to spawn a new instance of the same view - using the following code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
InventoryController *inventoryController = [[InventoryController alloc] initWithNibName:#"InventoryView" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self];
[navigationController pushViewController:inventoryController animated:YES];
[inventoryController release];
[navigationController release];
}
Problem is that it's not working...
I don't get any errors or anything - it just doesn't do anything.
Any ideas?
#PengOne has it right... you're creating a navigation controller and then releasing it, and there's nothing to prevent it from being deallocated. Additionally, you haven't added the nav controller's view to the window, and you haven't set the nav controller as the window's root view controller, so there's no way for the views controlled by controllers in this particular navigation stack to ever be seen.
Try this: Create a navigation-based project in Xcode. You don't need to add any code -- just create the project so that you can look at the code that's provided. You'll see that the app delegate has a retain property for storing the nav controller, and the nav controller is set as the window's root view controller.
If your current controller is already a part of UINavigationController hierarchy then you must not create a new navigation controller - use the existing one instead (note that every UIViewController has a reference to its parent UINavigationViewController if it exists):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
InventoryController *inventoryController = [[InventoryController alloc] initWithNibName:#"InventoryView" bundle:nil];
[self.navigationController pushViewController:inventoryController animated:YES];
[inventoryController release];
}
I am creating an application which I want to have a view controller with buttons as the first view controller with no navigation bar, and then when the user selects a button a table view controller appears managed by a navigation controller.
At the moment I am setting up the navigation controller in the app delegate and setting the top view controller as the table view controller I want to start the navigation bar on. So far I can see the navigation bar but that is it when I transition from the first view controller to the table view controller.
Any help would be much appreciated as I have confused myself with this issue.
I'm not totally clear on what you are asking, so I might have it wrong, but here goes.
The top navigation bar is can be displayed or hidden by calling:
self.navigationController.navigationBarHidden = NO;
In the viewWillAppear method of your viewController. So set it to YES or NO depending on whether or not you want it to be displayed.
#Disco, you would do something like so:
// In the App delegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
CustomViewController *viewController = [[CustomViewController alloc] init];
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
// In your button method
- (IBAction)loadUpTableViewController:(id)sender {
CustomTableViewController *tvc = [[CustomTableViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:tvc];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[tvc release];
}