Set UITabBarController created in Interface Builder as delegate - iphone

I created my iOS app with Tab Bar template, so here is UITabBarController with bar buttons. An issue is how to set it as delegate. I found at SO that it has to be set programmatically in AppDelegate, but I believe it's impossible, because I've got no access to Tab Bar Controller as outlet.
I added proper value to #interface (both ViewController and AppDelegate), but doesn't know what to do next.
#interface ViewController : UIViewController <UITabBarControllerDelegate>
I hope I don't have to get rid of whole app template and it's possible to set Tab Bar Controller created in IB to be delegate.
Exactly I want to make it delegate to create on tab select event like this:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController;
Any idea?

You can quickly and easily create a new TabBarController Delegate class and connect it as the delegate in the storyboard.
Create a new class :
class TabBarControllerDelegate: NSObject, UITabBarControllerDelegate {
In IB, add an object from the object library to the list of View Controller on the left (note: search "object", it's a yellow cube).
Change the class of this object (your yellow cube in IB) to TabBarControllerDelegate
In IB navigate to your Tab Bar Controller Scene. From the Connection Inspector, drag the delegate circle to the new object you added in Step 3.
Implement your delegate methods in your TabBarControllerDelegate class. Done!
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController)->Bool {
println("Selected a new tab")
}

I don't remember exactly the Xcode's Tab Bar template set up, but in your AppDelegate you can access to your window's rootViewController, cast it to a UITabBarController, and then set its delegate to your AppDelegate or to any other view controller.
Something like this:
UITabBarController *tabBarController =
(UITabBarController *)[[self window] rootViewController];
[tabBarController setDelegate:self]; // In this example your app delegate would implement the UITabBarControllerDelegate protocol.
EDIT
If you want to set your ViewController instance as the delegate:
UITabBarController *tabBarController =
(UITabBarController *)[[self window] rootViewController];
// I assume you have your ViewController instance set as the first view controller of your tab bar controller
// No need for a cast here since objectAtIndex: returns id, but of course you must implement the UITabBarController protocol in your ViewController.
[tabBarController setDelegate:[[tabBarController viewControllers] objectAtIndex:0]]];
EDIT 2
From your ViewController itself you can set the tab bar controller's delegate as rdelmar comments.
Just keep in mind that this cannot be done in the init method because the view controller is not in the tab bar controller yet. The proper place would be viewDidLoad but therefore it will not be executed until the ViewController view loads...
self.tabBarController.delegate = self;

0 lines of code
Drag an Object and subclass it
Xcode > Show File Inspector > Custom Class.
Class: TabBarControllerDelegate.
Set delegate to that Object
Put your existing code in that Object
This is the code you already have in your current UITabBarControllerDelegate.
class TabBarControllerDelegate: NSObject, UITabBarControllerDelegate {
// Delegate code goes here
}

What about create a viewController lets say MyTabController subclass UITabBarController
#interface MyTabController : UITabBarController<UITabBarControllerDelegate>
and set the tab Controller's class in you storyboard to MyTabController instead of UITabBarController, then put self.delegate = self; in your viewDidLoad
implement:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController;
and here you are.
Edit:
If you find self.delegate = self; is odd, which it is, you can create an outlet in your MyTabController
IBOutlet UITabBarController *tabBarController; and connect it to the tab controller in your storyboard.
Then you can put tabBarController.delegate = self;

Related

Using more than 1 UINavigationController and only one UITabBarController

I am having a problem with managing more than one UINavigationControlller.
I have a UITabBar and in every tab I have a separate UINavigationController. So If I switch in UITabBar by
tabBar.selectedIndex = i; // where i is index of tabbar.
and when I go back to previous tab by
tabBar.selectedIndex = previousIndex;
I go to the root of the UINavigationController, not the viewcontroller which I left previously.
I want to go to the viewcontroller from which I jump to another tab, without calling -viewDidLoad: or -viewWillAppear:.
I need a method which show either UINavigationController or my viewController.
The following method when implemented in your AppDelegate.m file will be fired whenever u try to switch the tabs
- (BOOL)tabBarController:(UITabBarController *)tbc shouldSelectViewController:(UIViewController *)viewController {
}
specify in your appDelegate class as the delagate of your tabbarcontroller
ie.( TabBarController.delegate = self) in appDidFinishLaunching method

tabBarController:shouldSelectViewController: not being called when delegate is set

I think I've done my homework here.
I want my app delegate to be the delegate for my UITabBarController.
Using IB, I've connected UITabBarController's delegate to my Application Delegate.
App Delegate Header file is:
#interface MyAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
The delegate method I'm trying to implement is:
-(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
NSLog(#"shouldSelectViewController called.");
// do some stuff with viewController
return YES;
}
My app delegate has an outlet to the UITabBarController that's connected in IB. When I do this:
NSLog(#"tab bar controller delegate is %#", self.tabBarController.delegate);
I get a good result such as tab bar controller delegate is <MyAppDelegate: 0x6e86a30>.
What am I missing?
Just write this code. Usually in viewDidLoad().
self.tabBarController.delegate = self;
If the current controller is a UITabBarController then:
self.delegate = self
Ok, found the solution. I had some old code in my RootViewController that set up this controller as the delegate. No delegate methods were implemented on the RootViewController, so it appeared as if nothing was happening. Because the RootViewController is set as delegate AFTER MyAppDelegate, the delegate was actually set to the RootViewController.
So the lesson is double-check your code to make sure some other object isn't also being set as the delegate.

how to reach tabBar

i have a navigation application with a tab bar and there is a web view in first view which is related with first tab bar item . with a button web view appears and i want to hide it when i touch the first tab bar item .. Please help thx
To get the controller, just:
[[tabBarController viewControllers] objectAtIndex:indexOfTheTab]
tabBarController refers to UITabBarController *tabBarController in you AppDelegate.
EDIT 1: add this to your AppDelegate.h
-(UITabBarController*)getTabBarController;
add this to your AppDelegate.m
-(UITabBarController*)getTabBarController { return tabBarController; }
Now, you can access it from everywhere:
[(AppDelegate*)[[UIApplication sharedApplication] delegate] getTabBarController]
Don't forget #import "AppDelegate.h"
EDIT 2: In you AppDelegate.m
In the first method, just add: self.tabBarController.delegate = self;
Then, override:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
//something like : [tabBarController hideTheStuffs];
}
With EDIT 2 you can listen to the user touches in the tab bar, even if the tab item is already the current one. With EDIT 1 you can access your delegate from everywhere if needed.
EDIT 3:
Do you have a IBOutlet UIWebView *myWebView in you ControllerView.h (the one with the view that shows the web view).
If not, add this outlet, then connect it to your webview in interface builder.
In the controller, add a method in .h and .m :
-(void)hideTheWebView { myWebView.hidden = YES; }
As this method is declared in the interface (.h), you can call it from the AppDelegate, method tabBarController:didSelectViewController.

TabBarController delegate is not working

Can any one help me,
when i am using my UITabBarController delegate it is not working..
I called a delegate method like this..
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
[self.navigationController popToRootViewControllerAnimated:NO];
}
If what you're doing is subclassing a UITabBarController, then... oddly enough... you can get it working by setting itself as a delegate:
- (void)viewDidLoad
{
[super viewDidLoad];
self.delegate = self;
}
Then the didSelectViewController action will fire normally:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
NSLog(#"View Changed");
}
Don't forget to add your UITabBarControllerDelegate class to your .h file:
#interface MyTabBarController : UITabBarController <UITabBarControllerDelegate>
#end
If you are using tab bar customizing by extending UITabBarController and trying to change tab bar selected index programmatically then it will not call delegates.
Please see the note inside "UITabBarDelegate":
// Note: called when a new view is selected by the user (but not programmatically)
This might help you
-(void)applicationDidFinishLaunching:(UIApplication *)application {
tabBarController.delegate=self;
// Add the tab bar controller's current view as a subview of the window
[window addSubview:tabBarController.view];
}
specify
UITabbarcontrollerDelegate in .h file
then
-(void)applicationDidFinishLaunching:(UIApplication *)application {
tabBarController.delegate=self;
// Add the tab bar controller's current view as a subview of the window
[window addSubview:tabBarController.view];
}
Read the documents to get a deeper understanding of the relationships between navigation controllers, tabBar controllers, and the view and navigation hierarchy.
Then review the code you've provided. Which view/controller is the container? You are popping the navigationController of self, which is not the same as the tabBarController. I don't think you actually need this method if you are looking to switch between tabs.
Try commenting out this method. It is an optional method in the UITabBarController delegate protocol. If you comment it out, you should get the default behavior of the tab controller, which should be to select the appropriate viewController and switch to the new view.
You typically only need to use this method if you want some action taken as you switch between view controllers.

Problem popping to root nav controller on tab bar switch

Trying to mimic/copy the built-in address book, specifically the behavior when editing a contact or viewing an existing contact's Info from inside the Phone app. When you navigate to another tab, the editing state is reset and the "New Contact" or "Info" view is popped so that when you come back to the Contacts tab, you are back at the root table view.
I have most of this working inside viewWillDisappear using setEditing: and popToViewController: however I get strange behavior when the user navigates from the Info view to the table view using the back button. Even if I pop to the root table view controller, it seems to be using the default UITableViewController class and not my subclass (e.g. standard selection behaviors instead of my overrides to push the detail view.)
Any hints? IPD
Here's some code to illustrate:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// This is to clean up from the colored bar in detail view
self.navigationController.navigationBar.tintColor = nil;
// These are to match the behaviour of Contacts app
[self setEditing:NO animated:NO];
// This is the tricky part: works when switching tabs, but not when back button was going to pop anyway!!
[self.navigationController popToViewController:rootViewControllerForTab animated:NO];
}
The -viewWillDisappear: method is not the best place for modifying the view controller stack for your navigationController because it is triggered both when you switch tabs and when a view is pushed on top of it.
I played around with this a bit and found that the best place for this is in the -[UITabBarControllerDelegate tabBarController:didSelectViewController:] method. So, first you need to designate an object to be the delegate for your tab bar (I used the app delegate). Bind the delegate property of your UITabBarController to an object implementing the UITabBarControllerDelegate protocol in code or in Interface Builder.
Then, implement the -tabBarController:didSelectViewController: method. The trick now is how to tell when your "address book" tab is being switched to. I kept track of the view controller for the tab in question using a property of type UINavigationController (the root view controller for the tab). After binding the tab1NavController property to the actual instance using Interface Builder, it can be used to compare to the viewController parameter to see what tab was just selected.
#interface Pop2RootTabSwitchAppDelegate : NSObject
<UIApplicationDelegate, UITabBarControllerDelegate> {
UINavigationController *tab1NavController;
}
#property (nonatomic, retain) IBOutlet UINavigationController *tab1NavController;
#end
#implementation Pop2RootTabSwitchAppDelegate
- (void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController {
NSLog(#"[%# tabBarController:%# didSelectViewController:%#]", [self class],
tabBarController, viewController);
if (viewController == tab1NavController) {
NSLog(#"viewController == tab1NavController");
[tab1NavController popToRootViewControllerAnimated:NO];
}
}