UINavigationViewContoller's rightBarButtonItem disappears once the application is pushed to background? - iphone

I have added rightBarButtonItem in a viewcontroller under viewWillAppear. its showing the button corretly.
- (void)viewWillAppear:(BOOL)animated {
UIBarButtonItem *addBarButtonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(add_Clicked:)];
self.navigationItem.rightBarButtonItem = addBarButtonItem;
}
but once i pushed application in background and bring it(applcation) to foreground the rightBarButtonItem got diappear?
I have debug that viewWillAppear get called once Application bring back to forground and the above line of code get executed also but then also the button does not comes up.

viewWillAppear is only called when you push a view on to the stack.
Place you code in the viewDidLoad.
When your app is send to the background, the viewDidUnload will be called, to reduce memory.
But sine your view is already presented it will not call the viewWillAppear.

Just tested this in a new Navigation-based project and I couldn't reproduce this.
One thing you can try is to call [super viewWillAppear:animated]; or check, if you setting the rightBarButtonItem to nil somewhere else.

Related

Presenting a ModalViewController inside a ModalViewController

I have a view which is presented as a modal view controller which takes username and password credentials. I want this view to check the delegate, and if the user hasn't previously set an unlock pin for the app, to then show the change pin view as a modal view controller. This is my code...
+(void)presentCredentialsViewController:(UIViewController *)vc{
CredentialsViewController *cvc = [[CredentialsViewController alloc] init];
[vc presentModalViewController:cvc animated:FALSE];
}
and then in CredentialsViewController
-(void)viewDidLoad{
[super viewDidLoad];
if([appDelegate.pin isEqualToString: #""]){
UserPrefsViewController *upvc = [[UserPrefsViewController alloc] init];
upvc.cancelButton.hidden = true;
[self presentModalViewController:upvc animated:FALSE];
}
}
But for some reason it doesn't work. The debugger steps through the code without error, never the less, the second modal view controller isn't displayed.
First, I would suggest checking that your appDelegate.pin is blank and not nil. If it is nil, the if statement would not be satisfied and your second ModalView would not be presented.
You may also want to try the previous suggestion, calling presentModalViewController from viewDidAppear, or setting a delay if leaving it in viewDidLoad. It is possible that the CredentialsViewController is trying to present the second view when it has not yet presented itself.
The if statement is being hit and the second PresentModalViewController is executing without error, but it just wasn't displaying. I did try putting the code in ViewDidAppear and a load of other places as well, such as applicationWillBecomeActive etc. Although not actually crashing the code, still none of these approaches would show the view controller. In the end I have opted for this:
start with pin of #""
on applicationDidEnterBackground check if pin has been set
if yes
PresentModalViewController: PinViewController
if no
do nothing
Bit of a hack but it will do for now. I suppose I should put some sort of notification in somewhere warning that the pin hasn't been set. The suggestion about the delay may possibly work I suppose. I might give it a go in the future. Thanks guys....points up!

UINavigationController and viewWillDisappear

So I have a UINavController in my app and am trying to execute a method when the user presses the back button. I have searched everywhere and can only find bits and pieces that don't really make sense out of context.
Is there a way to implement some sort of check that catches when the user presses the back button to dismiss the current view? (the viewWillDisappear method for the view being popped never gets called for some reason. I did read that it doesn't unless you forward that call?) Does that sound right, and does anyone have any ideas or suggestions? Thanks in advance.
Take a look at the UINavigationControllerDelegate. There are the only two methods that get called when a UIViewController is pushed to the navigation controller stack. Similarly, if one is being pushed then something probably was just popped. This is what I did to call viewDidDisappear and viewWillDisappear.
# pragma mark - UINavigationControllerDelegate Methods
- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
static UIViewController *vcPointer = nil;
// If the previous view controller is still around then let's send a viewWillDisappear message
if (vcPointer != nil) {
if ([vcPointer respondsToSelector:#selector(viewWillDisappear:)]) {
[vcPointer viewWillDisappear:animated];
}
}
// Keep track of a pointer to the current viewController
vcPointer = viewController;
[viewController viewWillAppear:animated];
}
This code keeps a pointer reference to the last view controller that was pushed so that once we push another one we can pop the last one (if it still exists).
AFAIK, if you add a UINavigationController to a UIView via code, it won't send those messages to it's subviews by default. It will only do this if the UINavigationController received these calls itself. Maybe this is your problem (I don't know your view setup).
So, when adding the view of the UINavigationController, be sure to manually send it these messages.
UINavigationController *navigationController = [UINavigationController alloc] initWithRootViewController:rootViewController];
[navigationController viewWillAppear:NO];
[aView addSubview:navigationController.view];
[navigationController viewDidAppear:NO];
At least, this is what I found during development. Been searching for this for a long time and I still don't understand the rationale behind it.
You can always hide the default back navigation button and create your own with its own method to be called when pressed.
Execute whatever code you want there then pop the view.
I used this solution:
Add a custom button on the left side in the navigation bar
Let that button activate a custom method.
Disadvantage of this workaround: you will lose that nice arrow shaped "back" button. That can be solved as well with a custom image.
So here is my code.
Put this in your viewDidLoad:
// LeftButton in Navigation Bar
UIBarButtonItem *leftBarButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:self action:#selector(backButtonPushed:)];
self.navigationItem.leftBarButtonItem = leftBarButton;
[leftBarButton release];
Then add this method in the same .m file:
- (void) backButtonPushed: (id)sender {
// do what you want to do
}
dont forget in the .h file
- (void) backButtonPushed: (id)sender;
The viewWillDisappear & viewDidDisappear is called when a controller is popped or dismissed. The function is called on the fore-front view controller not on the UINavigationController itself. Did you possibly subclass and forget to call the super on something?

UIViewController custom titleView crashes app

I have a navigation based iPhone app.
When you press on a cell in the tableview a new UIViewController is pushed to the navigation stack. In this view controller I am setting a custom titleView in the viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
// Setup custom navigation title
[self setTitle:#"Mediaportal"];
navItem = [[NavigationBarTitleItemViewController alloc] initWithNibName:#"NavigationBarTitleItem" bundle:nil];
[navItem setTitle:[theServer name]];
[navItem setSubTitle:#""];
[self.navigationItem setTitleView:navItem.view];
…
}
Once I switch back to the RootViewController:
[self.navigationController popToRootViewControllerAnimated:YES];
the app crashes with the following error (NSZombieEnabled=YES):
*** -[CALayer retain]: message sent to deallocated instance 0x5a5fd80
From what I can see the RootViewController still tries to access the custom titleView, which was deallocated with the second view controller. Once I comment out the custom titleView part in my code the app works.
I tried to set the navigationItem.titleView to nil (as found in the apple docs) before the second ViewController is deallocated, but that doesn't help.
Do you have a hint what I can do to prevent this crash?
Thanks,
Mark.
I had this exact same error a month or so ago, exactly the same situation. It drove me NUTS.
I discovered that the viewController i was popping too hadn't been deallocated at all. I had a custom UIButton subclass added to that view however that had been deallocated when the second view had been pushed. So when popping back, the UIButton wasn't there.
Check the view you are popping back to, to ensure you've not got any classes that you are deallocating, or are being autoreleased without you knowing.
Hope this helps.
I finally found the solution for it (a quite simple one).
I have to alloc and init the navItem through its property then it is being retained:
self.navItem = [[NavigationBarTitleItemViewController alloc] initWithNibName:#"NavigationBarTitleItem" bundle:nil];

using a button to navigate to different view in navigation based application?

i created a navigation based project but instead of tableview i added a new view with a button to navigate to the other view.. my button code is as shown below but whenever i run it the application doesn't run?? is the code wrong or navigation based application only work with tableview??
-(IBAction)clickMe:(id)sender
chdDetails *details=[[chdDetails dalloc]initWithNibName:#"chdDetails" bundle:nil];
[self.navigationController pushViewController:details animated:YES];
[details release];
details=nil;
It says "[[chdDetails dalloc]initW.... instead of alloc. is that a copy-waste typo?
No a navigationCOntroller will work with any viewController, you don't even need the navigationbar. I bet most application are navigationBased but you don't even see it.
[self.navigationController.navigationBar setHidden:YES]
Will do that.
Try placing a breakpoint in the clickMe method to test if it even gets called. What does this mean: "the application doesn't run??" is there an error message? Have you hooked the button up in IB? Is chdDetails a subclass of UIViewController? etc. etc.
Is chdDetails an UIViewController or an UIView? You can't push an UIView on an UINavigationController, only controllers.

popToRootViewController crashing

I am a relatively new iPhone app developer so my knowledge is a little sketchy, so please forgive me if this is a bit of a trivial question.
I have a navigation app which drills between table views by calling pushViewController on the navigationController object
I have one particular section which pushes new view controllers sequentially as the user goes through the interface. The view controllers are all subclassed from UIViewController.
It all works fine until it gets to the end, where the idea is the user presses a "Finish" button and is returned to the root view controller (main menu).
So on the button press I call:
[[self navigationController] popToRootViewControllerAnimated:YES];
And it crashes.
I am a bit worried this could be a big problem as this definitly worked at some point but it is now always failing.
Can anyone give any ideas/advice?
Some suggestions:
Before calling popToRootViewControllerAnimated: confirm that the RootViewController does actually exist. If it died somewhere along the line, calling the method will cause a crash.
Check the – viewWillDisappear: and – viewDidDisappear: methods of your last view to make sure you're not doing something dangerous there.
Not sure if popping a view causes it to always deallocate but check the dealloc method of the views and their controllers to make sure your not over-releasing something.
One mistake I've seen a lot is releasing objects in the data model from controllers. When another controller (in this case the RootViewController) tries to access the data model the app crashes.
It sound's like you need how to use the Xcode debugger. Type in debugger in Xcode help to get pointers.
You should not be using popToRootViewController in your viewWillDisappear.
Instead if you want to pop to root controller on your pressing the back button, you should replace the back button by your own and add an action to it. Try doing something like ::
UIBarButtonItem *back = [[UIBarButtonItem alloc] initWithTitle:#"back"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(goBack:)];
self.navigationItem.leftBarButtonItem = back;
and then handle the action as ::
- (void) goBack:(id)sender
{
// pop to root view controller
[self.navigationController popToRootViewControllerAnimated:YES];
}
As the others have commented, the first step is to run this is debug mode and figure out where and why you are crashing.
The most common type of crash is using a deallocated object (EXEC_BAD_ACCESS). Have you run the static analyzer? Are you properly retaining your object references?