Make ajax request upon programmatically switching tabBarController viewContoller - iphone

I've been reading through forum posts and banging my head for over 2hrs now and hopefully someone can help point me in the right direction.
I am using the UITabBarController and have 4 root views associated to it.
In the first view, the user can take a picture (UIImagePicker), after which the second view is displayed programmatically. Once the second view is displayed I want to make an ajax request to a server.
I am able to sucessfully select/display the second view with the following code:
self.tabBarController.selectedIndex = 1;
However the UITabBarControllerDelegate method (which is successfully called upon user tabBarContoller touches):
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
is not called, as Apple tabBarController:didSelectViewController documentation states:
In versions of iOS prior to version 3.0, this method is called only when the selected view controller actually changes. In other words, it is not called when the same view controller is selected. In addition, the method was called for both programmatic and user-initiated changes to the selected view controller.
So my question is: "How can I execute some code & make a request after programmatically switching to second view?"
I also tried putting traces in:
-(void)viewDidAppear
-(void)ViewWillAppear
-(void)viewDidLoad
but none of those are called when tabBarController.selectedIndex is set.
Many Thanks

viewWillAppear should be called.. I just tested it.
Another solution: use the UITabBarControllerDelegate with
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
for tracking changes.

Related

UITabBarController Weirdness ?

If I normally load up a UITabBarController and switch between views, it calls the viewWillAppear of each view controller.
But it is not so.
I want to switch to another tab as soon as another tab is touched.
If I specify a tab to load up - for example [self.tabBarController setSelectedIndex:0] in the viewWillAppear of one of the tabs (say tab 4)... It goes immediately back to tab 0.
But after that.... it does not call the viewWillAppear on any of the tabs when I switch between them.
For example, if I again go to tab 4, it does not come back to tab 0. I expect it to by a never ending cycle as I expect tab 0 to load up as soon as tab 4 is touch.
But it runs JUST ONCE !!
Why ??
Note: Question has been edited.
I think I found a solution. It works every time you click on your tab and it calls viewWillAppear on both tabs.
You can do this in your AppDelegate (or somwhere else in UITabBarController's delegate):
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
Sample code:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
if([self.tabBarController.viewControllers indexOfObject:viewController] == 1) {
[self.tabBarController setSelectedIndex:0];
}
}
setting the selectedIndex won't change the selectedViewController. You will have to change selectedViewController itself. Look at the documentation for more details.

UITabBar reload UIView on touch

Is it possible to call a method when a tab bar icon is touched, even if its already the selected icon? I want to make it remove a sub view when touched if the subview is showing.
I'm sure there must be a way to do this because I see it in other apps, but I cannot find any documentation on it.
From Apple Documentation for UITabBarDelegate :
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
Sent to the delegate when the user selects a tab bar item. (required)
As you noticed I think, and as stated by Apple docs, this message is sent only when a tab is selected
An important note, there is already a (not-documented?) default UIKit behavior of tapping a selected tab bar button :
If the tab contains a UINavigationViewController it will send to it a popToRootViewControllerAnimated: message. You can check this on any iOS application.
So beware before overriding this default (and user expected) behavior, which is, generally, a bad idea.
Apple has probably hidden what you want to do in its UIKit API, on purpose.
But if you want anyway does this, here are some ideas:
Small, but not easy hack: Once the tabBar has been displayed, recursively browse its .subviews tree to find (I expect, to be confirmed) UIButtons inherited classes (=private UITabBarButtons or something like) to add your target/selector pairs on TouchUp event (you might have to remove default behavior first, which might be tricky)
Worst solution, but might be the only one: Do not use UITabBar, but a custom class. I'm pretty sure there are ready-to-use open source components that mimics UITabBar, but sorry, I never used/searched one.
You can have delegates for the UITabbarcontroller,
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController;
Also please go through this document: UITabBarController delegate protocol

self.tabBarController.selectedIndex not calling viewDidAppear:YES

In a tabbar view when I call the tab to load useing self.tabBarController.selectedIndex the viewWillAppear is not called If i am been to the tab before hand is there a way to force the view to reload.
self.tabBarController.selectedIndex = 3;
[self.tabBarController.selectedViewController viewDidAppear:YES];
I was also thanking of dumping memory ever time i change tab's and that way when i get back to that view it reloads from the database.
you can implement
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
in the UITabBarControllerDelegate (probably your app delegate). Then in there you can manually call the methods you want on whichever index's viewController you selected.

viewWillAppear not called in UITableViewController?

I have a couple of UITableViewController classes and I just noticed that these methods aren't being called:
-(void)viewWillAppear:(BOOL)animated;
-(void)viewDidAppear:(BOOL)animated;
I read in http://discussions.apple.com/thread.jspa?threadID=1529769&tstart=0 that I would have to call those methods myself when pushing view controllers, but that's strange, since it works for anything but UITableViewController.
Also makes it a bit of an issue when I need to have a UITableViewCell deselected in the UIViewController that pushed the UITableViewController.
I can't find it in the documentation, but I think this might be because you are using a UINavigationController.
How about setting the UINavigationController's delegate property and then implementing UINavigationControllerDelegate? It provides two optional methods:
– navigationController:willShowViewController:animated:
– navigationController:didShowViewController:animated:
For example, navigationController:willShowViewController:animated: might look something like this:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if ([viewController isKindOfClass:[UITableViewController class]]) {
[viewController viewWillAppear:animated];
}
}
Anyway, this will get you the behavior you want without having to hack calls to viewWillAppear: all over your project.
Did anyone resolve this because the original post is correct - simply using UITableViewController and pushing the table view of that controller onto the navController does NOT trigger these methods despite the fact that it should. I have a series of UITableViewControllers and table views that are pushed and popped to display hierarchical data - nothing fancy, but the "viewWill/Did/Appear/Disappear" methods are never called. Only the viewDidLoad and viewDidUnload are called.
There must be a wiring problem in both our setups, but simply pushing a view into the navigationController should be all that is required (?) - hard to believe that this could have gone unnoticed as a fundamental bug this long.
?
These two methods are called by default to notify for the changes. UITableViewController is a subclass of UIViewController, so there will be the same behavior. You can see more in the View Controller Programming Guide
The viewWillAppear: and viewDidAppear: methods give subclasses a chance to perform any additional actions related to the appearance of the view.
How do you know that these methods are not called? Can you provide some more codes, or at least you test them with a NSLog() to see if there are some messages printed.
I'm seeing the same problem. I have a simple UIView from the IB and I do a addSubview with a class that extends UITableViewController.
I can see the view of the TableViewController without problems in my application, but the viewWillAppear function is never called in this situation.
Well, the discussion linked from the question has the answer right in it. UINavigationController needs to receive the "viewWillAppear" message in order for it to send those messages to the view controllers you push onto it.
So ironically if you don't do what Apple recommends, and you subclass UINavController for your view controller, then everything works great.
However, if you just create a UINavController inside of your view controller, then you need to implement "viewWillAppear", "viewDidAppear" and so on and forward those to your nav controller.
Note that this is especially important if you're using Three20, because its view controller hierarchy expects the "viewWillAppear" message to be received. If its not you can end up with TTTableViews that don't draw.
The same can occur if you use a UITabViewController. You need to force the viewWillAppear call by implementing either the UITabViewControllerDelegate or UINavigationControllerDelegate callbacks
This explanation may help: http://www.mlsite.net/blog/?p=210

How to automatically call a method after popping a view controller off the stack on the iPhone

I need to update the parent view on an iPhone after popping a child view off the navigation stack. How can I setup the parent view to be notified or receive an automatic method call when the child is popped off the stack and the parent becomes visible again?
The user enters data on the child page that I want to display on the parent page after the user is done and pops the view.
Thanks for you help!
I just resolved this self same problem - and the answers above are almost correct, they just forgot about setting the delegate.
I have a root view controller that displays the size of a list, calls a child view controller that may alter the size of a list, and must update the size upon return.
When I create my parent view (SettingsView below), and add it as the root view of a UINavigationController, I make sure to set the UINavigationController's delegate before I display the view - that's the key part:
SettingsView *sv = [[SettingsView alloc] initWithNibName:#"SettingsView" bundle:nil];
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:sv];
[nc setDelegate:sv];
In the parent view, implement the UINavigationControllerDelegate protocol:
#interface SettingsView : UIViewController <UINavigationControllerDelegate>
and provide the willShowViewController method:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// Your code to update the parent view
}
This is called after the child view is dismissed, and before the parent view is redisplayed.
I had the need to do something like this as well. In the ViewController that owned my UINavigationController, I had to implement willShowViewController, like this:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
}
That method is called whenever the UINavigationController changes views. If I'm understanding your question correctly, I think this should do what you want.
I think there is some confusion here. UIViews are not pushed to and popped from the UINavigationController's stack. What is being pushed and popped is UIViewControllers, which in turn handle one or (more often) several views each.
Fortunately, the UIViewController has these methods:
-(void) viewWillAppear:(BOOL)animated;
-(void) viewDidAppear:(BOOL)animated;
-(void) viewWillDisappear:(BOOL)animated;
-(void) viewDidDisappear:(BOOL)animated;
These are called whenever the view is about to (dis)appear, or has just (dis)appeared. I works with tab bars, modal views and navigation controllers. (And it's a good idea to make use of these when you implement custom controllers.)
So in your case, if I understand correctly, you simply have to override the viewWillAppear: or viewDidAppear: method on what you call the "parent page" (which is presumably handled by a UIViewController) and put in code to update the appearance of the page to reflect the data just entered.
(If I remember correctly, you must make sure that the UINavigationController gets a viewWill/DidAppear: message when it is first displayed, in order for these messages to later be sent to its child controllers. If you set this up with a template or in IB you probably don't have to worry about it.)
Felixyz answer did the trick for me. Calling the view will appear method will run the code in it every time the view appears. Different from view did load, which runs its code only when the view is first loaded. So your parent view would not update itself if a child view altered the info displayed in the parent, and was then popped off the sack. But if the parents calls view will appear, the code gets ran every time the view shows back up.
Make sure to call the super method at the same time. Proper implementation would look like this:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(#"View Appearing");
}
If you need to notify one controller to another you may use delegation pattern as described here (see 2nd answer).
Unfortunately there is no automatic notification(AFAIK) for exact task as you described.
To meet your needs you may send message to delegate (i.e. to your parent controller) in viewWillDisappear function of your child controller.