I have 2 versions of a tabbed ios5 application, one created using a storyboard and one using xib files. The storyboard version does not call the UITabBarControllerDelegate method didSelectViewController (the xib version does). Something is (I think) missing from the storyboard, but I don't know what. Another way of framing the question might be — how can I refer to the UITabBarController object instantiated by the storyboard?
Thanks for your help.
EDIT: The tab bar controller delegate is set:
In AppDelegate.h:
#interface MyAppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>
#property (strong, nonatomic) UITabBarController *tabBarController;
In AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.tabBarController.delegate = self;
return YES;
}
Then later in AppDelegate.m, the delegate method is:
- (void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
NSLog(#"Got Here");
}
The NSLog output never appears. The problem seems to me to be that I am not correctly referencing the tab bar controller object which has been instantiated by the storyboard.
How do I do that?
I had this issue.
If you're not using storyboards, setting the UITabBarController delegate in the AppDelegate is the way to go. However, with Storyboards, the AppDelegate has no idea where the tabBarController is on startup. You'd think by subclassing the tabBarController and adding the delegate method:
(void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController {
}
... would be enough. But, it's irritatingly not.
I needed to know when a user had pressed a tab button. I needed to know this more that I needed to know that the viewController's "- (void)viewWillDisappear:(BOOL)animated {}
" method had been run.
I decided to make my UITabBarController a delegate of itself. This seemed silly to me but I did the following...
#import <UIKit/UIKit.h>
#interface PlumbsTabBarController : UITabBarController <UITabBarControllerDelegate>
#end
And then, in my viewDidLoad method, wrote the following:
[self setDelegate:self];
Which enabled my tab bar delegate methods to run.
Crazy or what?
Ok - I'm editing this answer now, as even though the above is all correct, where a navigationController is being used, selected with each tabBarButton touched, the didSelectViewController delegate method will, when you try to NSLog(#"%#", viewController); only show you that you have selected the UINavigationController class?
So, the total solution, just to add more complexity, is to subclass the UINavigationController for each viewController that you want to monitor, (do something) when the tabBarbutton has been touched.
It works for me anyhow. And, if anyone can nit-pick through the above dribble, they might find an aspect that's useful - and that's enough for me - seeing as I find this site utterly useful too.
Put [self setDelegate:self]; in your ViewDidLoad or somewhere where the object get's initialized
Related
I have googled far and wide, but everything is extremely confusing. I need it so when the tab bar gets switched to a different view controller, is there a method that gets called when the view controllers are about to switch, get the destination controller and set some variables to add some annotations to a MKMapView. How can I do this?
There are many options, but one of them is to implement the UITabBarControllerDelegate protocol and then set the class that implements it as the delegate of your UITabBarController. The delegate receives a message - tabBarController:didSelectViewController:
In that method you can implement the behavior you desire by looking at the last view controller and the next one. To get access to those view controllers from your delegate, you may need to add them as weak properties to your delegate class. You can also access all of your UITabBarController's sub view controllers through its viewControllers property which is an array of view controllers.
After some experimentation with the delegate methods, I was able to find an answer.
I used the - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController method.
This feels like a fairly decent replacement because you can get each controller easily.
Warning: This method should not be used to handle large blocks of code, but to set up a view controller to run large blocks of code.
A test implementation:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
FirstViewController *currentController = (FirstViewController *)[tabBarController selectedViewController];
SecondViewController *destinationController = (SecondViewController *)viewController;
// If you want, do some code on these here. For more precision, read on.
return YES;
}
This can be used with logic to determine whether you should execute some specific code: EX:
if ([[tabBarController selectedViewController] class] == [FirstViewController class]) {
if ([viewController class] == [SecondViewController class]) {
// It is going from first to second. Do some code here.
}
}
Also, you have to have set the delegate
TabBarController .h
#interface TabBarController : UITabBarController<UITabBarControllerDelegate>
...
TabBarController .m
...
- (void)viewDidLoad
{
self.delegate = self;
}
...
I have a ViewController with 2 sub containers. The first sub container points to a ViewController with a TabBar inside it. The second sub container is a ViewController that contains a collection view. Now my issue is trying to access the first sub containers TabBar so that when an Item is clicked, I can know which item is clicked and process my data.
The main ViewController has a class. All the other sub containers for that ViewController also have a class. Here is the .h for my sub container with the Tab Bar:
#import <UIKit/UIKit.h>
#interface home_tab : UIViewController <UITabBarControllerDelegate>{
}
#end
.m:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
NSLog(#"working");
}
Now when clicking on the Tab Bar that is populated, didSelectViewController is never called.
I am using storyboard.
Suggestions and thoughts?
Try this on your viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
[[self tabBarController]setDelegate:self];
// Do any additional setup after loading the view, typically from a nib.
}
It's just an suggestion :)
[[self tabBarController]selectedIndex] This will return the index of the selected tab.
I think you have a couple problems atleast from what I can see here,
You are using a TabBar inside of a ViewController, not a UITabBarController, thus you need to use UITabBarDelegate not UITabBarControllerDelegate. You will have to manage the view controllers or whatever view you will want to be loaded on your own most likely with the delegate callback:
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;
Also you dont have a UITabBar defined in your controller, therefore your ViewController has no idea you have a UITabBar in your Storyboard. You need something like this:
#interface ViewController : UIViewController <UITabBarDelegate>
#property (weak, nonatomic) IBOutlet UITabBar *tabBar;
#end
Then you will need to Control drag from the ViewController to your UITabBar and back to connect the Delegate in your Storyboard.
Id recommend using a UITabBarController so you dont have to manage the views yourself depending on what you are trying to accomplish.
Hope this helps!
the didSelectViewController method is part of the UITabBarControllerDelegate Protocol and is called on the UITabBarController's delegate. Did you set the delegate of the tab bar controller to the current instance of your subcontainer? Inside ViewDidLoad: do something like this:
[self.tabBarController setDelegate:self];
You can also set a delegate on the UITabBar rather than the controller, and the UITabBarDelegate Protocol contains a method tabBar:didSelectItem: that would be called.
I started a new project with iOS 6 ARC and Storyboards
I made a very simple app that has a Tabbar and 2 views
so now I created a TestViewController file with is extending UITabBarController and I put the custom class in the storyboard.
now the issue is that I am trying to implement some delegate methods like
- (BOOL) tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController;
But it never calls it. Can anyone help?
I noticed too that if I put that code in the first view controller it works fine. It seems like the first view controller overwrites the TabBarController before. I am very confused.
for more testing I added in the TestViewController.m some logging:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"%#",self.tabBarController.viewControllers);
}
and the view controllers are null.
I even tried doing self.tabBarController.delegate = self;
But still no solution.
TestViewController is your tab bar controller, so your log should just be self.viewControllers, not self.tabBarController.viewControllers. You shouldn't need to add the property viewControllers either, since your subclass inherits that property from UITabBarController. The reason your delegate message is not called is because of the same problem. You should set the delegate with (in TestViewController):
self.delegate = self;
This is assuming that you want TestViewController to be the delegate, it wasn't clear to me if that's what you wanted.
Have you tried linking them in Interface Builder?
Add this to your header file first though
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
I have the problem that many already have reported, didSelectViewController doesn't get called, but in my case it sometimes gets called. I have three tabs and three view controllers. Every time user presses second or third tab I need to execute some code. In my SecondViewController and ThirdViewController I have:
UITabBarController *tabBarController = (UITabBarController *)[UIApplication sharedApplication].keyWindow.rootViewController;
[tabBarController setDelegate:self];
Now everything works fine with the SecondViewController, the didSelectViewController gets called every time the second tab is pressed. Also in ThirdViewController didSelectViewControllergets called every time the third tab is pressed but only when second bar is meanwhile not pressed. So when I switch back and forth between FirstViewController and ThirdViewController everything is OK. But when I go in a pattern like first->second->third, then didSelectViewController doesn't get called in ThirdViewController. Also when I go like first->third->second->third didSelectViewController gets called in ThirdViewController the first time but not the second time. Any ideas?
It's hard to follow what exactly you are doing, but from what I understand you are responding to tab switches by changing the UITabBarController's delegate back and forth between SecondViewController and ThirdViewController.
If that is true, I would advise against doing this. Instead I would suggest you try the following:
Assign a delegate that never changes. For a start you could use your app delegate, but it would probably be better if you had a dedicated small class for this. I am sure that now you have a non-changing delegate, it will get 100% of all the calls to tabBarController: didSelectViewController:.
The object that is the delegate must have a reference to both the SecondViewController and ThirdViewController instances. If you are designing your UI with Interface Builder, you might do this by adding two IBOutlets to the delegate class and connecting the appropriate instances to the outlets.
Now when the delegate receives tabBarController: didSelectViewController: it can simply forward the notification to either SecondViewController or ThirdViewController, depending on which of the tabs was selected.
A basic code example:
// TabBarControllerDelegate.h file
#interface TabBarControllerDelegate : NSObject <UITabBarControllerDelegate>
{
}
#property(nonatomic, retain) IBOutlet SecondViewController* secondViewController;
#property(nonatomic, retain) IBOutlet ThirdViewController* thirdViewController;
// TabBarControllerDelegate.m file
- (void) tabBarController:(UITabBarController*)tabBarController didSelectViewController:(UIViewController*)viewController
{
if (viewController == self.secondViewController)
[self.secondViewController doSomething];
else if (viewController == self.thirdViewController)
[self.thirdViewController doSomethingElse];
}
EDIT
Some hints on how to integrate the example code from above into your project:
Add an instance of TabBarControllerDelegate to the .xib file that also contains the TabBarController
Connect the delegate outlet of TabBarController' to the TabBarControllerDelegate instance
Connect the secondViewController outlet of TabBarControllerDelegate to the SecondViewController instance
Connect the thirdViewController outlet of TabBarControllerDelegate to the ThirdViewController instance
Add a method - (void) doSomething to SecondViewController
Add a method - (void) doSomethingElse to ThirdViewController
Make sure that you don't have any code left in SecondViewController and ThirdViewController changes the TabBarController delegate!
Once you are all set and everything is working fine, you will probably want to cleanup a bit:
Change the names of the notification methods doSomething and doSomethingElse to something more sensible
If you followed the discussion in the comments, maybe you also want to get rid of the secondViewController and thirdViewController outlets
I too had this problem and got fed up with it. I decided to subclass UITabBarController and override the following methods. The reason I did both was for some reason on application launch setSelectedViewController: wasn't being called.
- (void)setSelectedIndex:(NSUInteger)selectedIndex
{
[super setSelectedIndex:selectedIndex];
// my code
}
- (void)setSelectedViewController:(UIViewController *)selectedViewController
{
[super setSelectedViewController:selectedViewController];
// my code
}
I just dug through this tutorial on storyboards, and I thought of an alternative to using UITabBarControllerDelegate. If you want to stick to UITabBarControllerDelegate then feel free to ignore this answer.
First, create a subclass of UITabBarController, let's call it MyTabBarController. In the storyboard editor you need to change the "Class" property of the tab bar controller so that the storyboard picks up your new class.
Add this code to MyTabBarController.m
- (void) prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"SecondVC"])
{
SecondViewController* secondViewController = (SecondViewController*)segue.destinationViewController;
[secondViewController doSomething];
}
else if ([segue.identifier isEqualToString:#"ThirdVC"])
{
ThirdViewController* thirdViewController = (ThirdViewController*)segue.destinationViewController;
[thirdViewController doSomethingElse];
}
}
In the storyboard editor, you can now select the two segues that connect to SecondViewController and ThirdViewController and change the segue identifier to "SecondVC" and "ThirdVC", respectively.
If I am not mistaken, that's all you need to do.
I got TabBar Application with 3 ViewControllers.
Can i know from the ViewControllers's method which ViewContoller was desplayed before (1 or 2)? Or maybe i open VeiwController from some other .xib
You can do this by implementing UITabBarController delegate method -
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
}
in this you can check for [tabBarController selectedViewController] , here selectedViewController is the view controller which is currently selected and viewController is which is going to be selected.
I just creating #property in target VeiwController and set this #property firstly in viewDidLoad. So i know that firstly this ViewController will appear from TabBar. After that i can change it in some other ViewController's methods, which call some subviews (.xib).