I'm new to iOS development and have a question regarding variables. I'm attempting to write an application with a tab bar and navigation controller, the tab bar being the rootViewController. I've set up my application to include a .plist that includes my table view's behaviors, a UITableViewController, and a detail view controller. I continue to get one error in the implementation file of my initial table view controller as I defined the navigation controller in my App delegate.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//Get the dictionary of the selected data source.
NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
//Get the children of the present item.
NSArray *Children = [dictionary objectForKey:#"Children"];
if([Children count] == 0) {
DetailViewController *dvController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
}
else {
//Prepare to tableview.
IndustryTableViewController *industryTableViewController = [[IndustryTableViewController alloc] initWithNibName:#"IndustryTableViewController" bundle:[NSBundle mainBundle]];
//Increment the Current View
industryTableViewController.CurrentLevel += 1;
//Set the title;
industryTableViewController.CurrentTitle = [dictionary objectForKey:#"Title"];
//Push the new table view on the stack
[self.indNavControl pushViewController:industryTableViewController animated:YES];
industryTableViewController.tableDataSource = Children;
[industryTableViewController release];
}
}
I get the error when I push the new table view on the stack. I am importing the header file of my app delegate, but it still will not work, giving me the error, "Variable not defined in TableViewController.h". Is there a way for me to summon this variable, or is there a more effective way for me to solve this issue?
Thanks in advance, I can really use any help you give me.
You can get a pointer to your appDelegate and then get your variable like so:
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
Another way would be to use dependency injection and inject the reference into your controller when you create it. So basically define an ivar in your controller to hold a reference and then do this:
[myController new];
[myController setController:otherController];
You are referring to navigationController with self.navigationController.
This implies that navigationController is a variable defined in your TableViewController class.
You should define this variable in your class and modify your init method of the tableviewcontroller to receive that variable.
Related
I'm doing an application which uses a UINavigationController and I'm switching to other UIViewControllers as follows:
if(self.myViewController == nil){
MyViewController *aViewController = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
self.myViewController = aViewController;
[aViewController release];
}
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[delegate.myNavController pushViewController:myViewController animated:YES];
I imagine this is creating a pile of UIViewControllers into the UINavigationController, maybe an array of indexs? I would like to know how to turn back without having to be back one by one.
For example, I'm sailing through a few screens and with a button I would like to return at the first index of navigation. I would also like know how to modify indexes, view, erase and anything pertaining to this issue.
Sorry if I have not explained well.
You've asked two questions.
The first is, how do I get back to my first view controller. As #Thomas Clayson and #ender have answered, you want the popToRootViewControllerAnimated: method of your navigationcontroller object for that.
The second is how to move to a particular index in the view controller stack. The answer to that is, you can set the array of viewControllers explicitly. So you can pull out the current listing of view controllers, modify it, and set it back into the navigationController stack. It'll reset the stack and animate you moving to the top item in the stack.
Thusly:
NSMutableArray *controllers = self.navigationController.viewControllers;
[controllers removeObjectAtIndex:[controllers count] - 1]; //or whatever
[self.navigationController setViewControllers:controllers animated:YES];
NSArray *viewControllers = [[self navigationController] viewControllers];
for (int i = 0; i < [viewContrlls count]; i++){
id obj = [viewControllers objectAtIndex:i];
if ([obj isKindOfClass:[yourViewControllername class]]){
[[self navigationController] popToViewController:obj animated:YES];
return;
}
}
Using this you can come back to any specified viewController.
[self.navigationController popToRootViewControllerAnimated:YES];
Will take you back to the very first view controller (root view controller).
Hope this helps
Use this
NSArray *viewContrlls=[[NSArray alloc] initWithArray:[[self navigationController] viewControllers]];
id obj=[viewContrlls objectAtIndex:1];
[[self navigationController] popToViewController:obj animated:YES];
[viewContrlls release];
You should use popToRootViewControllerAnimated: From UINavigationController class reference:
Pops all the view controllers on the stack except the root view
controller and updates the display.
You can return to the first view with
[self.navigationController popToRootViewControllerAnimated:YES];
That being said, you can also remove a particular view controller, or navigate to a specific index in your view controller if you look at the example.
NSMutableArray *allViewControllers = [NSMutableArray arrayWithArray:navigationController.viewControllers];
// You can now manipulate this array with the methods used for NSMutableArray to find out / perform actions on the navigation stack
[allViewControllers removeObjectIdenticalTo: removedViewController];
// You can remove a specific view controller with this.
navigationController.viewControllers = allViewControllers;
I have a modal view that is a Navigation Controller. When one of the rows in its UITableView gets tapped, the correct View Controller for that row should be initialized and pushed onto the Navigation Controller's stack (so that the screen now shows that View Controller). But it's not working. I've been trying to debug it for a while, and it appears that the Navigation Controller's retain count is 0 at the time pushViewController is called. I assume that means it has been deallocated, and that this is the root of the problem. But I can't figure out why.
In the following code, AddSportDelegate.m presents the modal view that contains the necessary Navigation Controller (_addItemNavController) initialized with the necessary AddItemTableViewController. Tapping on one of the rows of the Table View managed by AddItemViewController calls the showAddItemDataView: method of AddSportDelegate, which in turn should push the correct ViewController onto the _addItemNavController stack. But, as I note in a comment in the code, the retain count of _addItemNavController at that moment is 0.
Note: I realize this code has memory leaks. I deleted some release lines for the sake of brevity. I also haven't included the code for the view controller that is supposed to be getting pushed, since it doesn't have anything at the moment beyond a UILabel identifying that it is the right View Controller.
AddItemDelegate.m
#synthesize addItemNavController = _addItemNavController;
- (void)showAddItemViewController:(UIViewController *)viewController
{
_parentVC = viewController;
[_parentVC retain];
tc = [[AddItemTableViewController alloc] init];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonSystemItemDone target:self action:#selector(cancelAdd)];
tc.navigationItem.leftBarButtonItem = cancelButton;
tc.title = #"Select a Category";
_addItemNavController = [[AddItemNavController alloc] initWithRootViewController:tc];
tc.superViewController = _addItemNavController;
[_parentVC.navigationController presentModalViewController:_addItemNavController animated:YES];
}
- (void)showAddItemDataView:(SportCategory *)category
{
[category retain];
UIViewController *vc;
if (category.name == #"Soccer") {
vc = [[AddSoccerDataViewController alloc] init];
}else{
vc = [[AddBaseballDataViewController alloc] init];
}
//retain count already 0
NSLog(#"retain count: %i", [_addItemNavController retainCount]);
[_addItemNavController.navigationController pushViewController:vc animated:YES];
}
AddItemTableViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
_addItemDelegate = [[AddItemDelegate alloc] init];
SportCategory *soccer = [[SportCategory alloc] initWithCategoryName:#"Soccer"];
SportCategory *baseball = [[SportCategory alloc] initWithCategoryName:#"Baseball"];
_categories = [[NSArray alloc] initWithObjects:soccer,baseball,nil];
[self.tableView reloadData];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
SportCategory *selectedCategory = [_categories objectAtIndex:[indexPath row]];
[_addItemDelegate showAddItemDataView:selectedCategory];
}
I am going to take a shot at this.
if (category.name == #"Soccer")
I come from a java background, but I know a little objective - c. I thought you can't compare strings with == which would mean your view controller was never created. Maybe try a isEqualToString method.
That is my only thought, I could be wrong. But Best of Luck.
The '==' operator isn't the good way to compare strings, but anyway your code should fall into the else part.
About your question, _addItemNavController must be nil because your NSLog prints 0 for its retain count.
Is the method -(void)showAddItemViewController:(UIViewController *)viewController called somewhere ?
Your view controller doesn't seem to be initialized.
A bit of sleep helped me find the problem. There were actually two:
1) The final line in AddItemDelegate read:
[_addItemNavController.navigationController pushViewController:vc animated:YES];
However, _addItemNavController IS the navigation controller, so the '.navigationController' part needed to be deleted.
2) I also needed to assign tc.addItemDelegate to self in showAddItemViewController.
I have spent several hours on this, and tried various things. I can confirm that the didSelectRowAtIndexPath is indeed being run, and the specific object I am looking for is being returned.
The bit that isn't doing anything is the part where I am trying to display the SensDetailViewClass view. It runs the code, but the viewDidLoad method in SensDetailViewClass.m doesn't run, and the view doesn't change.
I would like to have the SensDetailViewClass displayed. I can confirm that the .xib file's owner is the SensDetailsViewClass.
Please help. Here's the code.
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// get the selected item
Sens *info = [_sensInfos objectAtIndex:indexPath.row];
// initialise the detail view controller and display it
SensDetailViewClass *details = [[SensDetailViewClass alloc] initWithNibName:#"MainWindow" bundle:nil];
// set the title of the page
[details setTitle:info.heading];
details.selectedSens = info;
[self.navigationController pushViewController:details animated:YES];
[details release];
}
UPDATE: I got it to work by using this mechanism:
[self presentModalViewController:details animated:YES];
SensDetailViewClass *details = [[SensDetailViewClass alloc] initWithNibName:#"SensDetailViewClass" bundle:nil];
[self.navigationController pushViewController:details animated:YES];
i think you are fresher so nedd to check the link of tutorial
http://www.icodeblog.com/2008/08/03/iphone-programming-tutorial-transitioning-between-views/
Are you sure your SensDetailViewClass class has MainWindow as its .xib file?
Please check it and replace nib name `
initWithNibName:#"MainWindow"
in above code
Thanks,
1 ) Are you sure y*ou have the navigation comptroller in the app* or its just the View Based application.
IF this is ok then ,
2)
// initialise the detail view controller and display it
SensDetailViewClass *details = [[SensDetailViewClass alloc] initWithNibName:#"You-Xib name for this View" bundle:nil];
// set the title of the page
[details setTitle:info.heading];
details.selectedSens = info;
[self.navigationController pushViewController:details animated:YES];
[details release];
I've created an app that allows users to add information (from an addViewController), which is then displayed in a UITableView on the rootViewController. When the user taps the tableViewCell the detailViewController then displays, you guessed it, more details regarding the inputted user information. What I'm trying to accomplish is to setup an editViewController that will allow users to edit information they've already submitted.
Currently, I'm trying to auto-populate the editViewController with the information that was previously submitted by the user (after which they can press save and update the info). However, I'm getting stuck trying to perform this auto-populating and I'm not sure this is even the best route to accomplish this.
Here is the edit method that is called to load the editViewController from the detailViewController.
-(IBAction)editDetails:(id)sender {
editViewController *evc = [[editViewController alloc] initWithNibName:#"editViewController" bundle:nil];
rootViewController *rvc = [[rootViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:evc];
[[self navigationController] presentModalViewController:navigationController animated:YES];
///For Style
NSInteger styleCount = [[rvc scoreTypeArray] count];
NSInteger styleRows = [rvc.scoreTypeArray objectAtIndex:indexPath.row]; ///HERE I GET AN ERROR MESSAGE SAYING THAT indexPath IS NOT DEFINED
///For Date
NSInteger count = [[rvc dateArray] count];
NSInteger rows = [[rvc indexPath] row]; ///AND HERE I GET A WARNING MESSAGE SAYING rootViewController MAY NOT RESPOND TO INDEX PATH, AND OF COURSE IT DOESN'T WORK
[[evc dateField] setText:[NSString stringWithFormat:#"%#", [[evc dateArray] objectAtIndex:(count-1-rows)]]];
[[evc styleField] setText:[NSString stringWithFormat:#"%#", [[rvc scoresArray] objectAtIndex:(styleCount-1-styleRows)]]];
[navigationController release];
[evc release];
[rvc release];}
So here I'm trying to load the information from a saved array that is declared in my rootViewController.
Any thoughts any body?
Make propertyes in your edit view with retain, and then just edit the value. Retain just give you and reference to the original object. The setText on the text field just make an new copy of your string.
If you want to do this approch you can make an delegate protocol in your Edit view and set the current navigation controller that presents your edit view to be the delegate of yor edit view. And in your edit view when he will dissapear call the delegate method.
Delegate doc here
Declared property doc here
Good luck.
well...
NSInteger styleRows = [rvc.scoreTypeArray objectAtIndex:indexPath.row];
This is wrong because, you are trying to access indexPath.row which is not defined within this method. IndexPath.row is usually used within the tableView's methods like
(tableView*)didSelectRowAt:(NSIndexPath*)indexPath
So you will have to pass the value indexPath.row from the tableView's delegatemethods as a parameter in editDetails method.
but you actually dont need this... instead do this:
in detailViewController and editViewController, create a NSString *dateObject and make it of #property(nonatomic,assign).
Now in your root viewcontroller's didSelectRowAtIndexPath, when the user taps the row,
[dvc setDateObject:self.dateArray objectAtindex:indexPath.row];
so now, the detailViewController contains a reference to the original date in the dateObject. any change you make here will also change the date in the rootViewController's dateArray.
So when the use taps the edit button, call the
-(IBAction)editDetails:(id)sender {
editViewController *evc = [[editViewController alloc] initWithNibName:#"editViewController" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:evc];
[evc setDateObject:self.dateObject];
[[self navigationController] presentModalViewController:navigationController animated:YES];
[navigationController release];
[evc release];
}
Now you've again passed on the original dateObject to the editViewController. in its viewDidLoad, set the textField, and when the user edits and hits done, replace the dateObject in editViewController with the modified dateObject. Remember,this is the original dateObject that was passed as a reference from rootViewController. so you've replaced it there as well in rootViewController's dateArray. now you just need to know when you return from detailViewController to rootViewController and do a [table reloadData];
tadan!!!
First of all I know this is a long question. REST ASSURED I have tried to figure it out on my own (see: StackOverflow #2609318). This is driving me BATTY!
After trying and failing to implement my own EDIT feature in the standard moreNavigationController, I have decided to re-implement my own MORE feature.
I did the following:
Add a HOME view controller which I init with: initWithRootViewController
Add 3 other default tabs with:
ResortsListViewController *resortsListViewController;
resortsListViewController = [[ResortsListViewController alloc] initWithNibName:#"ResortsListView" bundle:nil];
resortsListViewController.title = [categoriesDictionary objectForKey:#"category_name"];
resortsListViewController.tabBarItem.image = [UIImage imageNamed:#"whatever.png"];
resortsListViewController.navigationItem.title=#"whatever title";
localNavigationController = [[UINavigationController alloc] initWithRootViewController:resortsListViewController];
localNavigationController.navigationBar.barStyle = UIBarStyleBlack;
[localControllersArray addObject:localNavigationController];
[localNavigationController release];
[resortsListViewController release];
Those work when i add them to the tabbar. (ie: click on them and it goes to the view controller)
Then I add my own MORE view controller to the tabbar:
MoreViewController *moreViewController;
moreViewController = [[MoreViewController alloc] initWithNibName:#"MoreView" bundle:nil];
moreViewController.title = #"More";
moreViewController.tabBarItem.image = [UIImage imageNamed:#"more.png"];
moreViewController.navigationItem.title=#"More Categories";
localNavigationController = [[UINavigationController alloc] initWithRootViewController:moreViewController];
localNavigationController.navigationBar.barStyle = UIBarStyleBlack;
[localControllersArray addObject:localNavigationController];
[localNavigationController release];
[moreViewController release];
Then
tabBarController.viewControllers = localControllersArray;
tabBarController.moreNavigationController.navigationBar.barStyle = UIBarStyleBlack;
tabBarController.customizableViewControllers = [NSArray arrayWithObjects:nil];
tabBarController.delegate = self;
That creates the necessary linkages. Okay, so far all is well. I get a HOME tab, 3 category tabs and a customized MORE tab -- which all work.
in the MORE tab view controller I implement a simple table view that displays all the other tabs I have in rows. SINCE I want to be able to switch them in and out of the tabbar I created them JUST like i did the resortslistviewcontroller above (ie: as view controllers in an array). When I pull them out to display the title in the tableview (so the user can go to that "view") i simply do the following:
// [myGizmoClass CategoryArray] holds the array of view controller tab bar items that are NOT shown on the main screen.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
... etc...
UIViewController *Uivc = [[myGizmoClass plusCategoryArray] objectAtIndex:indexPath.row];
cell.textLabel.text = [Uivc title];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
THIS is where it falls through:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MyGizmoClass *myGizmoClass= [MyGizmoClass sharedManager];
UIViewController *tbi = [[myGizmoClass plusCategoryArray] objectAtIndex:indexPath.row];
NSLog(#"%#\n",[[tbi navigationItem ]title]);
[self.navigationController pushViewController:tbi animated:YES];
}
This is the error i get ("ATMs" is the title for the clicked tableview cell) so i know the Uivc title is pulling the correct title and therefore the correct "objectatindex":
2010-04-09 11:25:48.222
MouseAddict[47485:207] ATMs 2010-04-09
11:25:48.222 MouseAddict[47485:207]
*** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason:
'Pushing a navigation controller is
not supported'
BIG QUESTION: How do i make the associated VIEW of the UIViewController *tbi show and get pushed into view?
I am GUESSING that the UIViewController is the correct class for this tbl .. i am not sure. BUT i just wanna get the view so i can push it onto the stack.
Can someone plz help?
To answer kovpas's question below: myGizmoClass is a singleton (apple's singleton myGizmo class. The array of viewcontrollers is stored in that just like it is in [localControllersArray addObject:localNavigationController]; (in the first code snippet above). AND it does put it in and pull it out correctly as evidenced by the fact that when i NSLOG the [Uivc title] the log prints ATMs. This means the plusCategoryArray is correctly storing and retrieving the viewController (if, indeed, that is what is being stored).
Pushing a navigation controller is not supported is really bothering me. Why would a viewController return a navigationController and is it possible to coerce the navigationController to get the "pushable" view out of it... or does the navigationController have some element in it that is the view?
From the error, it looks as if your Gizmo class has an array of UINavigationControllers, not UIViewControllers. So instead push with:
[self.navigationController pushViewController:[[tbi viewControllers] lastObject] animated:YES];
If the array is the same array as you called localControllers above, then this should work better. Or you could just create the array without the UINavigationControllers, they aren't needed if you are going to push them onto your more controller navigation controller.
I'm not sure, but it looks like this error appears when you are trying to push UINavigationController into another UINavigationController. Could you please provide an implementation of MyGizmoClass?