6

I have a storyboard project and I would like to pass some data from a view into a tab bar controller, the information will be spread out between the tabs. After doing some research I found a very similar issue: iOS storyboard passing data navigationViewController but the only issue with this solution is that it was not transferring to a tab bar controller. I was wondering would I have to pass the data to each tab or can I pass it to the tab bar controller and then spread it from there? Thank you for your help in advance!

I am currently using the following; but, I get an error:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
     if ([segue.identifier isEqualToString:@"FoodPage"]) {
    NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
    UINavigationController *nav = [segue destinationViewController];
    FoodViewController *destViewController = (FoodViewController*) nav.topViewController;
    destViewController.Foods = [foodArray objectAtIndex:indexPath.row];
  }
}

Community
  • 1
  • 1
paul590
  • 1,385
  • 1
  • 22
  • 43

2 Answers2

6

In order to get a reference to your UINavigationController in your case, you have to do the following and specify the correct index to your tabBarController first:

UINavigationController *nav = [self.tabBarController.viewControllers objectAtIndex:<THE_INDEX_NUMBER_FOR_YOUR_NAVIGATION_CONTROLLER];

Once you have done so, then you retrieve a reference to your FoodViewController by specifying again the index number for it on your UINavigationController (i.e. if it's on top, then 0):

FoodViewController *destViewController = (FoodViewController*) [self.nav.viewControllers objectAtIndex:0];

Update:

Now that I got a better idea what you would like to achieve:

You are using UITabbarController in which your others controllers are embedded.

Scenario / Example Case:

Let say we had 2 view controllers, controller A and controller B, respectively, both are embedded in a UITabbarController.

What we want:

We are trying to change the text of a UILabel in controller B from controller A.

First, declare a property in controller B in .h:

@property(strong, nonatomic) UILabel *aLabelInControllerB;

Second, declare a a property (or ivar) in your controller A:

@property(strong, nonatomic) ControllerB *controllerB;

Since you are using UITabbarController you don't need to use segue, you could simply get a hold of UITabbarController via self.tabBarController;

Question: "how would I know then when my tab bar controller is tapped and then change the text of the label in controller B?"

We do this:

Set controller A as the delegate of UITabbarController by:

In controller A .h, add:

@interface <Your_Controller> : UIViewController <UITabBarControllerDelegate>

In viewDidLoad of controller A:

self.tabBarController.delegate = self;

And in controller A .m, implement this method:

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
    self.controllerB = (ControllerB *) [tabBarController.viewControllers objectAtIndex:1];
    //In our example here, we only have 2 view controllers (A and B)
    //So, index 1 is where controller B resides.

    self.controllerB.aLabelInControllerB.text = @"Hello!";
    //This will change the text of the label in controller B
}

And as controller B appears, you will see that the text of the label will be changed to "Hello!"

Setting a NSString in controller B follows the same procedure.

Ex: self.controllerB.stringInControllerB = @"Hi from controller B!";

Hope that helps.



Update 2:

Segue'ing from table view cell to a tab bar controller? Oki.. Here is the solution. I am only using one cell in my example, so should it become desired that you would like to have more cells in the future, I would leave that up to you to adjust.

Let's take a look at the storyboard layout:

In storyboard, control drag from your cell to the tab bar controller.

Add a UINavigationController like in the picture.

In your UITableViewController .m:

Add 2 properties:

@property (strong, nonatomic) UITabBarController *myTabbarController;
@property (strong, nonatomic) YourFirstViewController *myFirstViewController;

Just a friendly reminder:

Remember to add:

self.tableView.delegate = self;
self.tableView.dataSource = self;

Add the following in your table view controller:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    self.myTabbarController = (UITabBarController*) [segue destinationViewController];
    self.myFirstViewController = [self.myTabbarController.viewControllers objectAtIndex:0];
    self.myFirstViewController.stringFromTableViewController = @"Hi from TableViewController!";
}

And in myFirstViewController, add 2 properties in .h:

@property (strong, nonatomic) NSString *stringFromTableViewController;
@property (strong, nonatomic) YourSecondViewController *secondViewController;

Like from the second edit above, have your first view controller to be still the delegate of UITabBarControllerDelegate and implement this method:

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
    self.secondViewController = (YourSecondViewController*) viewController;
    self.secondViewController.aLabel.text = self.stringFromTableViewController; 
}

Just like before, nothing needs to be changed in SecondViewController.

I ran this myself; should be good to go for your setup.

Enjoy.

Unheilig
  • 16,196
  • 193
  • 68
  • 98
  • When you refer to the index are you referring to which tab index to send the information to or the index of the tab bar controller? Also, where would I get the index of the tab bar controller? Thanks again! – paul590 Jan 22 '14 at 00:42
  • 1
    @paul590 Yes, if you have, let say, a `UINavigationController` on the second tab, then the corresponding index number would be 1 on your `tabBarController`. So, you first need to get a hold of that by specifying 1 as index; once you get a hold of the `UINavigationController`, you would need again to specify an index for your `FoodViewController`, which normally, as I presume, would be `0`, on the top. – Unheilig Jan 22 '14 at 00:52
  • Sorry let me clarify that I have a tableview of food in which when the user selects a food it will send this information to a tab bar controller where there is the food name tab, description tab, and how to make it tab. Would I still use the same information you provided me with? – paul590 Jan 22 '14 at 01:00
  • @paul590 That's correct. When you have a `tabBarController` in which your other controllers are embedded, you first need to get a reference to the controller you wish to get a hold of by specifying the index number on the `tabBarController`, once you get a hold of the controller from the `tabBarController`, then you send the information to that controller. So, in your case, you need to get a hold of the controller from the `tabBarController` by specifying the tab (index); once that is done, then you send the data to it. – Unheilig Jan 22 '14 at 01:06
  • Thank you for explaining it, it makes a lot of sense! I am currently trying your code but I am getting an error on this line FoodViewController *destViewController = (FoodViewController*) [self.nav.viewControllers objectAtIndex:0]; it says property nav not found in foodlistviewcontroller. Do i have to create the nav outside the segue? – paul590 Jan 22 '14 at 01:34
  • @paul590 No, if you don't have a `UINavigationController` you don't need that. But since that's what you wrote in your question, I thought you had a `UINavigationController`. If you don't, simply specifying the index for `FoodViewController` in your `tabBarController` should do the job. – Unheilig Jan 22 '14 at 01:37
  • i see! would I end passing the information the regular way as well? for example: food.string = @"hello"; – paul590 Jan 22 '14 at 02:42
  • Def will do I am just trying to understand the way to send the information still, it is not sending to the view for some reason. I have the following code: – paul590 Jan 23 '14 at 01:06
  • - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"FoodPage"]) { FoodViewController *destViewController = (FoodViewController*) nav.topViewController; destViewController.FoodString = @"hello"; } – paul590 Jan 23 '14 at 01:08
  • I meant food.FoodString = @"hello"; }** Would I also include the passing of information to the other tabs in this segue? – paul590 Jan 23 '14 at 01:10
  • Thank you for the help this is definitely useful, but unfortunately it is not what I am looking for unless I am understanding incorrectly. I have added a picture to my question to clarify what I would like to do. The methos that you provided me with will help me once I'm inside the tab controller but if I want to import a string from outside the tab controller I would still need a segue? – paul590 Jan 24 '14 at 04:14
  • Can you let me know the solution in Swift 3? – Pavlos Mar 11 '17 at 18:25
2

It's also possible to access data from the TabBar within the TabBar's child viewcontrollers themselves, like so:

MyTabbarViewController *tabbar = (MyTabbarViewController *)self.tabBarController;
NSLog(@"%@", tabbar.data);

This way you only have to set the data in the TabBar like shown above, and then access it whenever you need it in a child view.

Tum
  • 6,937
  • 2
  • 25
  • 23
  • Used this solution, easiest one. Not completely sold on having the child view controllers of the tabbar controller to know of it's parent though. – José Oct 14 '15 at 13:46