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];
}
}
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.
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.
Related
How can I pass data between a Navigation Controller and a Table View Controller? I have tried prepareForSegue method but it doesn't work.. I have tried to put a breakpoint to see if the flow calls this method but it seems that the prepareForSegue of my Navigation Controller class is never called. Here is some sample of code :
NavController.h :
#interface NavController : UINavigationController
#end
NavController.m :
- (void) prepareForSegue: (UIStoryboardSegue *) segue sender: (id) sender
{
TableViewController *destViewController = (TableViewController*)segue.destinationViewController;
destViewController.title = #"Home";
destViewController.URLValue = #"http://www.example.com";
}
TableViewController.h :
#interface TableViewController : UITableViewController
#property (nonatomic, strong) NSString *URLValue;
#end
It sounds like the navigation controller is your root view controller (ie, if you select the navigation controller scene and inspect its details in Xcode, the "Initial Scene" checkbox should be checked). Because it's the initial scene and is arrived in only one way, try setting default values in viewDidLoad: on your TableViewController.
I am stuck with a problem and can't find a decent solution. I am trying to add a name in parent ViewController and show them in a UITableView but to add a new name I go to a AddVC where I add a name via a UITextField and I want to add the name in the NSMutableArray from the parentVC.
Let me restate what I think you're asking: You have a ParentVC and you want to segue to a ChildVC that will present a UITextField to enter a name. Once the name is entered, you want to return the name back to the ParentVC. If this is correct then within your ChildVC prepareForSegue method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// if you're using a nav controller (modal)
//UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
//ParentVC *destinationVC = (ParentVC *)navController.topViewController;
// if you're not using a nav controller (push)
ParentVC *destinationVC = (ParentVC *)segue.destinationViewController;
// assuming you have a public property in your ParentVC.h such as:
// #property (strong, nonatomic) NSString *theNewName;
destinationVC.theNewName = myAddNameTextField.text;
}
Take an NSMutableArray as a property in your AppDelegate . Always fetch the Array from AppDelegate. If you add something. Just add in this global mutable array. This way it won't matter where you add object in array and where from you fetch .
In my storyboard, I have a Table View Controller and I want to be able to tap on an item in the table view and go to a detail view with more information. In the detail view, I'd like it to be like the Tab Bar Controller as the detail view can be separated into 2 categories.
Is this possible? At the moment I can do it in my storyboard, but after searching around, I can't seem to find out how to pass the details of the selected item from the Table View Controller to the Tab Bar controller.
Am I missing something obvious? Or going about this wrong? I'm new to iOS development so any advice would be appreciated.
Thanks!
Have you tried passing the information to one of the TabBarController's view controllers in a property through the prepareForSegue method?
Create two properties in the TableView Controller:
#property (strong, nonatomic) UITabBarController *tabBarController;
#property (strong, nonatomic) YourViewController *firstViewController;
Then Use:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"prepareForSegue: %#", segue.identifier);
if ([segue.identifier isEqualToString:#"mySegueID"]) {
self.tabBarController = (UITabBarController*) [segue destinationViewController];
self.firstViewController = [self.tabBarController.viewControllers objectAtIndex:0];
self.firstViewController.SOMEPROPERTY = SOMEVALUE;
}
}
I am getting an error while passing data from a table view controller to a detail view
controller. I am using a navigation controller along with it.
The error message is as follows:
use of undeclared identifier _wordLabel
This is the prepare for segue implementation in my table view controller (.m file).
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"ShowWordDetails"]) {
//UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
wordDetailViewController *detailViewController = [segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView indexPathForSelectedRow];
long row = [myIndexPath row];
detailViewController.wordDetailModel = #[_wordLabel[row], _meaningLabel[row]];
}
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
I have previously declared wordLabel and meaningLabel in the detail view controller as follows:
#property (strong, nonatomic) IBOutlet UILabel *wordLabel;
#property (strong, nonatomic) IBOutlet UILabel *meaningLabel;
#property (strong, nonatomic) NSArray *wordDetailModel;
I have also declared it in viewDidLoad method of detail view controller as follows:
-(void)viewDidLoad {
[super viewDidLoad];
_wordLabel.text = _wordDetailModel[0];
_meaningLabel.text = _wordDetailModel[1];
// Do any additional setup after loading the view.
}
_wordLabel is private member of your detailViewController. You can't access it like you're trying to do in the first code quote. You need to call detailViewController.wordLabel instead.
first of all you can't use the array operator with a UILabel
_wordLabel[row]
second of all you have to define the _wordLabel[row] as an array in the TVC, that is separate from the label in the detailViewController
I think you don't require wordDetailModel as you can access UILabel from TableViewController as described below
detailViewController.wordLabel.text = #"Word";
detailViewController.meaningLabel.text = #"Meaning";
_wordLabel is UILabel and it is private variable in DetailViewController which can not be used directly from TableViewController, you have to use it using property. Plus _wordLabel is not an array as already answered by #sha and #rockstarr
I have two ViewControllers, which aren`t (directly) connected with a Segue. But I want to change a String in the second VC, which i get in the first one. My try was:
#import "secondViewController.h"
#interface firstViewController ()
#property NSString* originalString;
#end
#implementation firstViewController
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
secondViewController* svc = [secondViewController new];
svc.anotherString = self.originalString;
}
But it dosent work, because I've only created a instance of the second VC, so the value was not saved. Also I can`t use the Storyboard ID, because I use Xcode 5.
I have a menuVC from which you can get to the firstVC and the secondVC. And from the firstVC I can go back (with the navigationbackbarbutton) to the menu. so: menu->firstVC->menu. menu->secondVC->...->menu
My try with StoryboardID:
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
secondViewController* svc =[[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:#"secondVCSrorybradID"];
svc.anotherString = self.originalString;
}
you can pass the string to second view controller with this code.
secondViewController* svc =[self.storyboard instantiateViewControllerWithIdentifier:#"Your Second VC's Storyboad ID"];
svc.anotherString = self.originalString;
[self presentViewController:svc animated:YES completion:nil];
//you have to create anotherString property in second View Controller's .h File.
now you can get the string of originalString to second VC. Now you can get this value back second VC to first VC.
hope this helps you.
You should pass your data successively through your UIViewControllers navigation. If, for example, you have a navigation like FirstVC > SecondVC > ThirdVC :
In your FirstVC.m, use :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
((SecondVCClass*) segue.destinationViewController).secondVCString = _firstVCString;
}
With secondVCString being a #property in your second ViewController.
In your SecondVC.m, use :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
((ThirdVCClass*) segue.destinationViewController).thirdVCString = _secondVCString;
}
With of course thirdVCString being a #property in your third ViewController.
Edit:
As you updated your question, here is what I suggest :
In your MenuVC, add this :
#property (nonatomic, weak) NSString *importantString;
In your FirstVC and SecondVC, add this :
#property (nonatomic, weak) MenuVCClass *menu;
When you push to FirstVC or SecondVC, use prepareForSegue to set the destination's view controller menu property to your menu :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"FirstSegue"])
((FirstVC*) segue.destinationViewController).menu = self;
else if ([segue.identifier isEqualToString:#"SecondSegue"])
((SecondVC*) segue.destinationViewController).menu = self;
}
In FirstVC or SecondVC, you can change the NSString value from your menu using _menu.importantString = #"";
You should never use new to create a view controller.
If you're using storyboards but not using segues, you can still create a view controller from the storyboard and invoke it.
Use the method instantiateViewControllerWithIdentifier: to create an instance of the target view controller. The set the properties you want to set, and finally make a call to display it (present it modally, push it onto the navigation stack, or whatever is appropriate for your program.)