I have been having trouble with what seems to be a fairly simple problem but I can't for the life of me work it out.
My initial view is a single view not embedded in anything where the user logs in. After they press a button I want to transition to a view that is part of a 2 tabbed UITabBarController that is also embedded in a UINavigationController. I have tried every type of Segue but I either get a NSInvalidArgumentException with the UITabBarController or it takes me to the next view but the tab bar and the navigation bar do not appear on the screen.
Hopefully this is detailed enough to understand what I am trying to do, if it is not I can upload a picture of my storyboard.
Edit - Here is my storyboard and my prepareForSegue method
Storyboard : http://oi60.tinypic.com/2pyub0o.jpg
#property (nonatomic) int numberOfPlayers;
#property (strong, nonatomic) UITabBarController *tbc;
#property (strong, nonatomic) MPAMainViewController *mvc;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"startGameSegue"]){
self.numberOfPlayers = [[self.textField text] intValue];
self.tbc = (UITabBarController *) [segue destinationViewController];
self.mvc = [self.tbc.viewControllers objectAtIndex:0];
self.mvc.numberOfPlayers = self.numberOfPlayers;
}
The error I am currently encountering is "-[UINavigationController setNumberOfPlayers:]: unrecognized selector sent to instance 0x7fc103493380"
Thanks!
Related
I'm having a small problem with my push segue on Xcode Im trying to push the content of one label to another one on a different view controller, this is my current setup no errors are present and but the text on the other view controller doesn't change to match the previous window.
The first example below is my detailviewcontroller which I'm sending the information from. I have created the push segue between the detail view controller and my new view controller which is CODEVIEW and given the segue the name ShowCode.
I was wondering if I was missing line of code which would automatically activate this segues information without the need of a button but instead works when loaded.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"ShowCode"]) {
CODEVIEW *CodeSender = [segue destinationViewController];
CodeSender.CODElabel.text = _Code.text;
}
}
Label outlet for CODEVIEW
#property (strong, nonatomic) IBOutlet UILabel *CODElabel;
Label outlet for detail view controller
#property (strong, nonatomic) IBOutlet UILabel *Code;
In your current VC:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"ShowCode"]) {
CODEVIEW *CodeSender = [segue destinationViewController];
CodeSender.codeLabeltext = _Code.text;
}
}
In your target/next VC:
a) inside CODEVIEW.h interface:
#property (strong, nonatomic) NSString *codeLabeltext;
#property (strong, nonatomic) IBOutlet UILabel *CODElabel;
b) in your CODEVIEW.m implementation:
- (void)viewDidLoad {
[super viewDidLoad];
//...
_CODElabel.text = codeLabeltext;
//...
}
I have two views. The main view is ViewController and the next is AddItemViewController. ViewController has a tableview that lists items that you add when you go to AddItemViewController. There is a button on AddItemViewController that segues back to ViewController. The problem is, upon returning to ViewController expecting that an item be added, the private data of ViewController is suddenly set to nil. I have lost data and any chance to interact with my objects after returning from the segue.
Here is the data that's getting set to nil
#property (strong, nonatomic) costEstimator *myCost;
#property NSString *testString;
What am I doing wrong?
Here is my prepareforsegue code in the AddItemViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
ViewController *vC = [segue destinationViewController];
[vC addSomething:_selectedItem withQuantity:[_quantBox.text doubleValue]];
}
Any help is greatly appreciated. Thanks :)
You want to pop the AddItemViewController in this case. When you segued from ViewController to AddItemViewController, I am guessing you did a push. What this does effectively is it adds AddItemViewController ontop of ViewController in the memory stack. By 'segue-ing' again from AddItemViewController to ViewController, you are adding ANOTHER ViewController instance ONTOP of AddItemViewController. This is why you think you are losing your data when in actuality, you aren't. You are only seeing the wrong view controller.
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 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.
I'm doing an Ipad app. Now I have 2 viewcontrollers, ViewController has a button1 which has a popover segue to the second viewcontroller(PopoverController). Then, the PopoverController has a button2, if I click the button2, I'll receive some UIImage from my server. I want to add fews subviews of UIImageView to the ViewController to display these images if I click the button2.
The button1 works well, the PopoverController can pop up as expected. BUT when I click the button2, nothing happend. I want to know how can I pass the data between 2 viewcontrollers and how to add subviews to another one.
Some codes relating to my problem:
ViewController.h:
#import <UIKit/UIKit.h>
#class PopoverController;
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UIButton *button1;
#property (strong, nonatomic) PopoverController *popoverController;
#end
PopoverController.h:
#import <UIKit/UIKit.h>
#class ViewController;
#interface PopoverController : UIViewController
#property (strong, nonatomic) IBOutlet UIButton *button2;
#property (strong, nonatomic) UIImage *tempImg;
#property (strong, nonatomic) ViewController *viewController;
- (IBAction)addsubviews:(id)sender;
#end
I can not just use [viewController.view addSubview:img1]; in the - (IBAction)addsubviews:(id)sender;method to addsubview. So someone can help me? :)
====1st update====
Someone suggest that I have to use - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender method. I have tried this one by control click the button2 and create a custom segue between button2 and ViewController. When I clicked the button2, it showed :
Terminating app due to uncaught exception 'NSGenericException', reason: 'Could not find a navigation controller for segue 'change'. Push segues can only be used when the source controller is managed by an instance of UINavigationController.'
So I'm wondering whether I should add a NavigationController. If so, what should I do?
====2nd update====
I use Paramasivan 's code now, and I found the way to call method from another viewcontroller. The problem now is the newly added subview in my viewcontroller doesn't show up. I guess I have to update my viewcontroller in order to make it visible.
in my - (IBAction)addsubviews:(id)sender; method, i invoke the method in ViewController by [self.viewController createSubViewWithImage:_tempImg];
so the method can be invoked when i click the button2, but the view of viewcontroller has nothing changed.
Add this in - (void)viewDidLoad,
self.popoverController = [[PopoverController alloc] init];
self.popoverController.viewController = self;
Make sure that in no other places, you are setting self.popoverController = ....
Do NOT add anything like self.viewController = ... in popovercontroller class. And you dont have to do self.viewController.popoverController = self; as well. Just remove these lines if you already have it.
Once these are done, make sure that you are displaying self.popoverController only in the popover and you are not creating a new object for popoverController class there. So if these are fine, you can use any approach you want for passing the image from popoverController class to viewController class.
as you mentioned in your comment you can use [self.viewController createSubViewWithImage:_tempImg]; in your popovercontroller class.
Update:
If you are doing via storyboard, you need to set this in prepareForSegue method and you dont have to create self.popoverController at all. Remove that part in your case. You can follow the procedure mentioned here to set up a custom segue and implement prepareForSegue method to pass the object. Source: On storyboards, views and passing data along
Set the name of segue in storyboard to "CustomSegue"
Implement prepareForSegue method
Inside the method, check if name of segue matches "CustomSegue" and then set the viewController in the popoverController object there as,
Try,
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"CustomSegue"]) {
PopoverController *popoverController = [segue destinationViewController];
popoverController.viewController = self;
}
}
After doing this, you need to call [self.viewController createSubViewWithImage:_tempImg]; in your popoverController class.
Check out the Communicating with Objects doc, there are several ways to do what you want.
In ViewController.h add the following
-(void)createSubViewWithImage:(UIImage *)imageDownloaded {
UIImageView *imageViewTemp = [[UIImageView alloc] initWithImage:imageDownloaded];
[self.view addSubView:imageViewTemp];
}
In PopoverController.h add the following
#property (nonatomic, retain) ViewController *viewControllerPassed;
And after image downloaded, call the following in PopoverController.h
[viewControllerPassed createSubViewWithImage:imageDownloaded];
You can pass data using the below method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ViewController2"])
{
ViewController2 *v2VC = [segue destinationViewController];
v2VC.yourData = self.someStuff;
}
}