Pushing and Popping View Controllers - iphone

I have a navigation view controller which is a table view and then from the table view if i select a row it goes into detail view page. When i go to the detail view page i retrieve some information from the server and if the server does not respond then i get an alert view pop up which appears in front of my parent navigation view. now when press ok on the alert view and click on another row and it does go into my "didselectview" method but does not go to my detail view page. Would anyone know why? Code given below.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//Navigation logic may go here. Create and push another view controller.
Item *selectedItem = (Item *)[self.fetchedObjectsArray objectAtIndex:indexPath.row];
NSString * urlString = [CONST_FEED_DISCRIPTION_URL stringByAppendingString:selectedItem.guid];
NSDate * dateString = selectedItem.date;
JsonViewController *jsonViewController = [[JsonViewController alloc] initWithURLString:urlString date:dateString];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Back"
style:UIBarButtonItemStyleBordered
target:nil
action:nil];
self.navigationItem.backBarButtonItem = backButton;
self.navigationController.navigationBar.tintColor = [UIColor colorWithHexString:CONST_NAVIGATIONBAR_COLOR];
[self.navigationController pushViewController:jsonViewController animated:YES];
[backButton release];
[jsonViewController release];
}
The first time around you get the alert view (which is an error message). After that nothing happens when u click on a row. but i know it goes into the method given below. would anyone know why? Does it have something to do with me pushing views? and not popping them?

Defer the push until the next runLoop, to let the tableView return:
dispatch_async(dispatch_get_main_queue(), ^ {
NSLog(#"Going to push...");
NSLog(#"...view Controller %#", jsonViewController);
[self.navigationController pushViewController:jsonViewController animated:YES];
[jsonViewController release];
NSLog(#"Just pushed %#", jsonViewController);
) );
Just to be clear, remove both these lines from the existing code:
[self.navigationController pushViewController:jsonViewController animated:YES];
[jsonViewController release];

Related

navigationController issue

I have the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath(NSIndexPath*)indexPath
{
audiChassisInputViewController = [[myAudiChassisInputViewController alloc] init];
[self.navigationController pushViewController:audiChassisInputViewController animated:YES];
self.navigationController.navigationBarHidden = NO;
UIBarButtonItem *retourButton = [[UIBarButtonItem alloc] initWithTitle:#"Retour" style:UIBarButtonItemStyleBordered target:self.navigationController action:#selector(popViewControllerAnimated:)];
[self.navigationController.navigationBar.topItem setLeftBarButtonItem:retourButton];
[self.navigationController.navigationBar.topItem setTitle:#"Chassis Input"];
[retourButton release];
[audiChassisInputViewController release];
}
and this workes...the new view is showed.
in the new view:
myAudiChassisInputViewController.h
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
chassisInputTextView.layer.cornerRadius = 15;
chassisInputTextView.clipsToBounds = YES;
[chassisInputTextView becomeFirstResponder];
UIBarButtonItem *okButton = [[UIBarButtonItem alloc] initWithTitle:#"OK" style:UIBarButtonItemStyleBordered target:self action:#selector(chassisOkPressed)];
[self.navigationController.navigationBar.topItem setRightBarButtonItem:okButton];
[okButton release];
}
I have no error, but there is no right bar button shown.Anyone, any idea why?
Change this line:
[self.navigationController.navigationBar.topItem setRightBarButtonItem:okButton];
with this line:
[[self navigationItem] setRightBarButtonItem:okButton];
The thing is, by the time viewDidLoad is executed, the top item of the navigation bar (self.navigationController.navigationBar.topItem) is still pointing to the navigation item of the back view controller.
The back view controller is the one that used to be the top view controller before the current top view controller was pushed onto the stack ([[viewControllers objectAtIndex:[viewControllers count] - 2] navigationItem]). The following snippet shows how the top item of the navigation bar is still pointing to the navigation item of the back view controller in viewDidLoad and it is for illustration purposes only:
// the view controllers currently on the navigation stack
NSArray *viewControllers = self.navigationController.viewControllers;
// The root view controller is at index 0 in the array, the back view controller is at index n-2, and the top controller is at index n-1, where n is the number of items in the array.
UIViewController *backViewController = [viewControllers objectAtIndex:[viewControllers count] - 2];
// get the navigation item of the back view controller
UINavigationItem *backNavigationItem = backViewController.navigationItem;
UINavigationItem *topItem = self.navigationController.navigationBar.topItem;
if (backNavigationItem == topItem) {
NSLog(#"This gets logged to the console");
}
Go to your
myAudiChassisInputViewController.m file
place following code
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIBarButtonItem *retourButton = [[UIBarButtonItem alloc] initWithTitle:#"Retour" style:UIBarButtonItemStyleBordered target:self.navigationController action:#selector(popViewControllerAnimated:)];
UIBarButtonItem *itemOkey=[[UIBarButtonItem alloc] initWithTitle:#"OK" style:UIBarButtonItemStyleBordered target:self action:#selector(chassisOkPressed)];
self.navigationItem.rightBarButtonItem=itemOkey;
self.navigationItem.leftBarButtonItem=retourButton;
}
I have the valid output as follows that you want to have
Hope it helps to you.
If you have xib file of your class, then add the navigation controller and add the navigation bar and under that add the UIBarButton.

My navigationbar doesn't show a back button if the previous view controller has no title

How do i make it show the back button, with the title "Back"? It shows perfectly well if the previous view controller has a title.
Simplest solution is in viewDidLoad of the view that is about to push a new one, do the following:
UIBarButtonItem *backBarButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleBordered target:nil action:nil];
self.navigationItem.backBarButtonItem = backBarButton;
[backBarButton release]
Works perfectly, no questions asked.
You can set the backBarButtonItem property of the previous viewController. So if you are have one viewcontroller "A" and you push a viewController "B". The back button will be the button backBarButtonItem on the "A" view controller.
You can also try to set the title before pushing the new view controller. For example:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self setTitle:#"back"];
// Push new view controller...
}
and then set it back to #"" in your -viewWillAppear.

How to disable a DetailViewController UIBarButtonItem from RootViewController?

i have a main table view. and a DetailView. when cell is clicked, DetailView of that cell comes which shows details of that cell. DetailView has two buttons next and previous. I wanna know how to disable a detail view button from RootViewcontroller.m. code looks like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *nextController = [[DetailViewController alloc] init];
int storyIndex = [indexPath indexAtPosition:[indexPath length] -1];
nextController = [nextController initWithObjectAtIndex:storyIndex inArray:stories];
NSString *storyTitle = [[stories objectAtIndex:storyIndex] objectForKey:#"title"];
nextController.title = #"Details";
UIBarButtonItem *tempButtonItem = [[[UIBarButtonItem alloc] init] autorelease];
tempButtonItem.title = #"Back";
self.navigationItem.backBarButtonItem = tempButtonItem ;
nextController.sTitle = storyTitle;
[self.navigationController pushViewController:nextController animated:YES];
[nextController release];
}
i have already tried nextController.next.enabled=NO and [nextController.next setEnabled:NO] after this line:
[self.navigationController pushViewController:nextController animated:YES];
where next is the UIBarButtonItem name which is in DetailViewController.
can anybody tell me how to disable that button.
thanx in advance
Viewcontrollers and views are not loaded at the same time. What this means is that when you instantiate an object of DetailViewController in your case, the views are not drawn(and if you are using Nib's) loaded, this is part of the lazy loading concept.
So the first time you send the message setEnabled = NO, the object will be nil(sending messages to objects that are nil is allowed in Objective C).
Example:
[nextController setEnabled:NO] is equal to [nil setEnabled:NO] and this is surely not what you want.
The next time, unless a memory warning and the views are unloaded, the views will be in memory and the reference to the button will no longer be nil so the second time you invoke it, it will work.
And add the code line above the pushViewController:animate
If you want to initialize the button to be disable you may put this code in the viewDidLoad/viewWillAppear depending on the context of your application.
This is only one possible solution.
Edited answer to request in comment:
In your initializer method in the DetailviewController add this:
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleBordered target:self action:#selector(backToRoot)] autorelease];
- (void)backToRoot {
[self.navigationController popToRootViewControllerAnimated:YES];
}
and also add the method-signature to your headerfile.
Reference to the UINavigationController: http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html

How do I add a button to my navigationController's right side after pushing another view controller in?

So, immediately after pushing a view controller to my tableView,
// Override to support row selection in the table view.
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here --
// for example, create and push another view controller.
AnotherViewController *anotherViewController =
[[AnotherViewController alloc] initWithNibName:#"AnotherView" bundle:nil];
[self.navigationController pushViewController:anotherViewController animated:YES];
Ok, so that makes another view slide on, and you can go back to the previous view ("pop" the current view) by clicking the button that automatically appears in the top left corner of the navigation bar now.
Ok, so SAY I want to populate the RIGHT SIDE of the navigation bar with a DONE button, like in the "Notes" app that comes with the iPhone. How would I do that?
I tried code like this:
UIBarButtonItem * doneButton =
[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:#selector( doneFunc ) ];
self.navigationController.navigationItem.rightBarButtonItem = doneButton ; // not it..
[doneButton release] ;
doneFunc is defined, and everything, just the button never appears on the right side..
The code you posted should work fine, I think. Question is, where did you put it? I would put it into the -viewDidLoad method of the view controller you're pushing in. If you need different buttons depending on the content you're showing then you could do it in the -viewWillAppear: method.
Update: Actually, I think you need to change
self.navigationController.navigationItem.rightBarButtonItem = doneButton;
to
self.navigationItem.rightBarButtonItem = doneButton;
AH. You have to do:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
AnotherViewController *anotherViewController =
[[AnotherViewController alloc] initWithNibName:#"AnotherView" bundle:nil];
[self.navigationController pushViewController:anotherViewController animated:YES];
UIBarButtonItem * doneButton =
[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:#selector( doneFunc ) ];
anotherViewController.navigationItem.rightBarButtonItem = doneButton ;
[doneButton release] ;
}
Who'da thunk it.

Weird UI problem when modal view is dismissed

As shown in the screenshot below, i have a UITableView with some info and upon selecting a row an ABUnknownPersonViewController is invoked. In order to be able to able to dismiss that and go back to the UITableView I have this code:
ABUnknownPersonViewController *unknownPersonView = [[[ABUnknownPersonViewController alloc] init] autorelease];
[unknownPersonView setUnknownPersonViewDelegate:self];
[unknownPersonView setDisplayedPerson:personRecord];
[unknownPersonView setAllowsAddingToAddressBook:YES];
UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithTitle:#"Επιστροφή" style:UIBarButtonItemStylePlain
target:self action:#selector(goBackToView)];
unknownPersonView.navigationItem.title = #"Προσθήκη στις επαφές";
unknownPersonView.navigationItem.leftBarButtonItem = anotherButton;
navigationController = [[[UINavigationController alloc] initWithRootViewController:unknownPersonView] autorelease];
//navigationController = [[[UINavigationController alloc] initWithRootViewController:self] autorelease];
//self.navigationItem.rightBarButtonItem = anotherButton;
[self presentModalViewController:navigationController animated:YES];
} // didSelectRowAtIndexPath ends here
- (IBAction)goBackToView {
[self dismissModalViewControllerAnimated:YES];
}
- (void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownPersonView didResolveToPerson:(ABRecordRef)person {
// CallerIDAppDelegate *delegate = (CallerIDAppDelegate *)[[UIApplication sharedApplication] delegate];
[navigationController dismissModalViewControllerAnimated:YES];
}
The problem (as you can see) is that when the ABUnknownPersonViewController is dismissed by the "Επιστροφή" button, which is "Back" actually, the view holding the tableView and the blue UIButton is moved a couple of pixels to the bottom!
Any help on what could be causing this?
Screenshot http://dl.getdropbox.com/u/1237004/problem.jpg
Debug this by checking your view's frame in -viewWillAppear, -viewDidAppear, -viewWillDisappear, and -viewDidDisappear.
Also check the view's autoresizingMask, and the parent view's autoresizesSubviews property.
I'm not sure I see the value of setting up a navigation controller here. You could just present the ABUnknownPersonViewController with [self presentModalViewController: unknownPersonView];. If you're doing it for the sake of picking up the visual navigation bar with the back button, then just add a nav bar and button to the unknown person view.
It seems like a mixed metaphor to be creating a UINavigationController but then not using its usual navigation methods (e.g., pushViewController:animated: and popViewControllerAnimated:) and instead using the modal methods inherited from UIViewController.
It seems that adding this line:
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
in my viewWillAppear: made the view not to move when the modal view controller is dismissed. However now the initial position was already slightly dislocated to the bottom but fixed it by moving all the outles in IB to the top so it looks ok.