Update UIViewControllers after switching of the tabbar selection - iphone

I have two view controllers in a tabbar which can both edit data. Therefore, I need to call a reload_data function whenever the user makes a switch on the tabbar. How can I catch the switch or the appearance of the viewcontroller. Somehow viewDidAppear is not called on a tabbar switch. And I do not want to use the tabbarController delegate for this, because several viewControllers are affected (and I cannot set them all as delegate). What is a good way to solve this?
e.g. this didn't work:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[self reloadData];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
[self reloadData];
}

If you're using Interface Builder, make sure the class for the viewController your expecting to reload is defined (Select the ViewController in IB, then CMD-4, make sure class is defined to be the class you want viewWillAppear and viewDidAppear to be called in).
If you're not using IB, post your code for init/calling the viewController.

Related

How to hide navigation bar in iPhone?

Currently i am working in iPhone app, I have two screen like A and B, A has no navigation bar, but B has navigation bar. so i set like this.
Class A:
- (void)viewDidLoad
{
[super viewDidLoad];
self.title=#"A";
[self.navigationController setNavigationBarHidden:YES];
}
-(void)viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES];
}
Class B:
- (void)viewDidLoad
{
[super viewDidLoad];
self.title=#"B";
[self.navigationController setNavigationBarHidden:NO];
}
-(void)Previousscreen
{
[self.navigationController popViewControllerAnimated:YES];
}
then i run the application, When i go to previous class like B to A at the time blue color show in B class below attached screen shot for your reference. How to fix this issue? please help me
Thanks in Advance
Set it in class B
-(void)viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:NO];
}
You'll need to use this code:
[navigationController setNavigationBarHidden: YES animated:YES]
in - (void)viewWillAppear:(BOOL)animated or later in the view lifecycle in both classes. [Avoid doing this in - (void)viewDidLoad.]
The trick here is in using the setNavigationBarHidden:animated: method (in place of the simpler setNavigationBarHidden: method). This will ensure your UI issue goes away and also any positional issues due to it.
P.S. Check the value of self.navigationController.navigationBarHidden (instead of self.navigationController.navigationBar.hidden) if you need to check if your navigation bar is hidden, at some point, in your code.
I don't think a behavior when you are hiding and showing the navigation bar dynamically as you are pushing controllers is supported.
Simple solution - hide the animation bar of the UINavigationController and if you want to show it on some controller, just add a UINavigationBar to it.
Use below line to hide navigationBarin viewWillAppear: method -
-(void)viewWillAppear:(BOOL)animated
{
self.navigationController.navigationBar.hidden=YES;
}
Try setting the navigationBarHidden: in viewWillDisAppear of class B
in class B
-(void)viewWillDisAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES];
}
Your code is okay for Hide and Unhide the navigationBar. The problem is that you're hiding Class A's navigationBar in viewWillAppear: which is called just before appearing the view so before loading the Class A view navigationBar is being hidden each time.
And if we talk about your blue color i think it is your window color. Because after hidden the navigationBar there will be a space above your self.view which height is 44.0. So there are three options to fixed it.
Hide Class A's navigationBar in Class A's viewDidAppear: method.
Set your window color what you want to show.
You can add an image to window background in which at top of image make a navigationBar same as Class B's navigationBar so when the original navigationBar will be hide it will see.
I've had to solve this recently and I found that it was necessary to call setNavigationBarHidden:NO immediately after pushViewController: and setNavigationBarHidden:YES immediately after popViewController:, with animated YES in each call.
So, when pushing:
[nc pushViewController:classBView animated:YES]
[nc setNavigationBarHidden:NO animated:YES]
and when popping:
[nc popViewControllerAnimated:YES]
[nc setNavigationBarHidden:YES animated:YES]
But in my case, while I could do pushing as above, I didn't want to alter my class B and instead wanted it to not know of care that the navigation bar wasn't previously hidden (since its not my code). Also, that view gets popped using the normal Back button, there was no explicit call to popViewControllerAnimated:. What was going to work best in my code was to make my class A be the UINavigationController delegate and hide the toolbar on a delegate method call when the pop occurs.
Unfortunately I found that the UINavigationControllerDelegate methods weren't too helpful, willShowViewController & didShowViewController are called indistinguishably when pushing my class B view or when popping back to it from another one that it has pushed.
I followed a suggestion in https://stackoverflow.com/questions/642312/ about overriding UINavigationController and I made some custom delegate methods, one is called right after [super popViewControllerAnimated:]. My subclass is available at https://gist.github.com/jpmhouston/6118713 and delegate method is:
- (void)navigationController:(UINavigationController *)navigationController isPoppingViewController:(UIViewController *)poppedViewController backTo:(UIViewController *)revealedViewController {
if (revealedViewController == self && [poppedViewController isKindOfClass:[MyClassB class]]) {
[navigationController setNavigationBarHidden:YES animated:YES];
// ...and more code to run only when going from class B back to class A
}
}
I'm sure there are simpler ways to have setNavigationBarHidden: called following the Back button being pressed, but this worked for me.

viewDidAppear not getting called

In my main UIViewController I am adding a homescreen view controller as subviews:
UINavigationController *controller = [[UINavigationController alloc] initWithRootViewController:vc];
controller.navigationBarHidden = YES;
controller.view.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
[self addChildViewController:controller];
[self.view insertSubview:controller.view atIndex:0];
[controller didMoveToParentViewController:self];
The issue is that viewDidAppear and viewWillAppear is only called once, just like viewDidLoad. Why is this? How do I make this work?
Basically inside vc I am not getting viewDidAppear nor viewWillAppear.
I also just tried adding the UIViewController without the navigation controller and it still doesn't work:
vc.view.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
[self addChildViewController:vc];
[self.view insertSubview:vc.view atIndex:0];
[vc didMoveToParentViewController:self];
In my case, viewDidAppear was not called, because i have made unwanted mistake in viewWillAppear method.
-(void)viewWillAppear:(BOOL)animated {
[super viewdidAppear:animated]; // this prevented my viewDidAppear method to be called
}
The only way I can reproduce the problem of child controllers not receiving appearance methods is if the container view controller does the following (which I'm sure you're not doing):
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers
{
return NO;
}
Perhaps you can try explicitly enabling this:
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers
{
return YES;
}
But my child view controllers definitely are getting the viewWillAppear calls (either if I explicitly automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers or if I omit this altogether.
Update:
Ok, looking at the comments under your original question, it appears that the issue is that the child controller (B) in question is, itself, a container view controller (which is perfectly acceptable) presenting another child controller (C). And this controller B's own child controller C is being removed and you're wondering why you're not getting viewWillAppear or viewDidAppear for the container controller B. Container controllers do not get these appearance methods when their children are removed (or, more accurately, since containers should remove children, not children removing themselves, when the container removes a child, it does not receive the appearance methods).
If I've misunderstood the situation, let me know.
#Rob answer in Swift 4 (which helped me on my case which I was adding a childViewController to a UITabBarController)
override var shouldAutomaticallyForwardAppearanceMethods: Bool {
return true
}
Another case where this will not be called at launch time (yet may be called on when you return to the view) will be is if you have subclassed UINavigationController and your subclass overrides
-(void)viewDidAppear:(BOOL)animated
but fails to call [super viewDidAppear:animated];
Had a same problem
My container view controller did retain a child view controller via a property, but did not add a child view controller to its childViewControllers array.
My solution was to add this line of code in the container view controller
[self addChildViewController: childViewController];
After that UIKit started forwarding appearance methods to my child view controller just as expected
I also changed the property attribute from strong to weak just for beauty
When updating my code to 13.0, I lost my viewDidAppear calls.
In Objective-c, my solution was to add the following override all to the parent master view controller.
This allowed the ViewDidAppear call to get called once again...as it did in previous IOS (12 and earlier) version.
#implementation MasterViewController
//....some methods
(BOOL) shouldAutomaticallyForwardAppearanceMethods {
return YES;
}
// ...some methods
#end
My problem was that I was changing the tab in UITabBarController (selectedIndex = x) and then messing with the child view controllers in that tab. The problem is that it needs to be done the other way round: first mess with the child view controllers in other tab and then change the tab by setting the selectedIndex. After this change methods viewWillAppear/viewDidAppear begun to be called correctly.
Presenting view controllers using presentModalViewController or segues or pushViewController should fix it.
Alternatively, if for some reason you want to present your views without the built-in methods, in your own code you should be calling these methods manually. Something like this:
[self addChildViewController:controller];
BOOL animated = NO;
[controller viewWillAppear:animated];
[self.view insertSubview:controller.view atIndex:0];
[controller viewDidAppear:animated];
[controller didMoveToParentViewController:self];

what's called after returning from presentModalViewController / dismissModalViewControllerAnimated:

to show a modal uiview out of my mainView I use:
[self presentModalViewController:myController animated:YES];
and in MyController I close that view with:
[self dismissModalViewControllerAnimated:YES];
But how can I know in the mainView that the modal was finished (to redraw my table)?
Currently I set a local variable to YES in my mainView after starting the modal view an react on viewWillAppear:
[self presentModalViewController:myController animated:YES];
_reloadTableData = YES;
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (_reloadTableData) {
_reloadTableData = NO;
[_tableView reloadData];
}
}
Is there a better way to do so ?
Generally speaking, it's not appropriate to dismiss the modal view by the modal view itself.
Instead, you should set your main view as the delegate of the modal view. When you modal view finishes its task, it can let its delegate know and let its delegate dismiss it. This is the very common so-called delegate design pattern in Objective-C.
btw, you may want to consult with some code samples to gain a better understanding of this delegate pattern. I suggest you take a look at one of Xcode's default templates - the Utility Application template. It has a very succinct and simple and straightforward delegate structure built inside.

Perform an action when tabBarController changes

I have a tabbar application that has one screen that displays statistics based on the data presented in the tableviews of over tab screens. I would like to refresh this view once the stats view becomes selected again. I have implemented the tabbarcontrollerdelegate protocol to take an action when the viewcontroller.tabbaritem.title isequaltostring:#"foo". which works fine for my nslog statement but when i try and trigger the viewcontroller to execute the viewdidload method it never happens. And the code to refresh the stats view is in the viewdidload method.
From my AppDelegate
- (void)tabBarController:(UITabBarController*)tabBarController didEndCustomizingViewControllers: (NSArray*)viewControllers changed:(BOOL)changed
{
}
- (void)tabBarController:(UITabBarController*)tabBarController didSelectViewController:(UIViewController*)viewController {
if([viewController.tabBarItem.title isEqualToString:#"Summary"]) {
NSLog(#"didSelectViewController %#", viewController.tabBarItem.title);
[viewController viewDidLoad]; //FAIL
}
}
Never call viewDidLoad by yourself. That is a delegate method that is sent to the view controller after the view has loaded, you shouldn't call it manually.
In this case, view controllers that have views which are managed by a tab bar controller are sent the viewWillAppear:, viewDidAppear:, viewWillDisappear: and viewDidDisappear.
You should should use these methods to perform actions when your views are shown and hidden.
Example: implement viewDidAppear: and refresh your stats view.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated]; // don't forget to call super, this is important
// do your refreshing here
}

presentModalViewController viewDidLoad not being called

I have an event which calls a view to appear, but the -viewdidload event isn't appearing as expected each time it's called. Here's the method I use to call it...
[self presentModalViewController:addItemViewController animated:YES];
then inside the addItemViewController, the method is
- (void)viewDidLoad {
NSLog(#"alright, lad!");
}
To close the view, I have a button with the code
- (IBAction)cancel {
[self dismissModalViewControllerAnimated:YES];
}
the "alright, lad" log is shown the first time the view appears, but never again when it's launched. Is there a method I can use to let the app "forget" about the view? Or should I be using another load method? I tried loadView (I think) but that had a blank screen...
Thanks for any help!
viewDidLoad is only called when the view is first instantiated. If you're not recreating the view controller each time, you'll only get it called once (and called again if you get a memory warning, and the view is nil'd out). You probably want to use viewWillAppear: or viewDidAppear:.
Make sure you call the superclass in each of those methods, e.g.
- (void)viewWillAppear:(BOOL)animated {
NSLog(#"view appeared");
[super viewWillAppear:animated];
}