Passing data from a View to another view inside a tabcontroller - ios

I am having issues passing data from a View to another view that has a relationship with a Tab Controller. I got it to work from one view to another view...
if I set the segue from the mainView directly to the secondView, it works! however if i set the segue to go to the tab bar controller (which will call the secondView), it does`t...
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender(id)sender {
secondView *secView = [segue destinationViewController]
secView.ext = #".com";
}
If I had to guess I would say that destinationViewController is the problem.. as the destination view controller is the tab bar controller and not the secondView

Look at what you wrote, and look at your code -- you've essentially answered your own question. You've connected the segue to something other than an instance of secondView. Then, you get the segue's destinationViewController (which you know is a tab controller) and treat it as though it were a secondView.
You don't say how it fails, but I wouldn't be surprised if you get an error to the effect that UITabBarController doesn't have a -setExt: method.

You can do 2 things:
Create a Tab Bar Controller class, add a property inside it, assign it a value in prepareForSegue, then use [self.tabBarController] in secondView.m to access it, or
Change your secondView *secView = [segue destinationViewController] line to:
secondView *secView = [[[segue destinationViewController] viewControllers] objectAtIndex:0]

Related

Perform Segue With Identifier for already Instiated View Controller

I'm trying to use a custom segue (at bottom) to present a view controller modally with a blur view. I need to instantiate the view controller with properties before I present the view controller.
Instating the VC works great when I am using pushVC, but when I use perform segue with identifier, I don't see an option to choose an already instantiated VC.
CustomViewController* VC = [self.navigationController.storyboard instantiateViewControllerWithIdentifier:#"customVC"];
[self.navigationController performSegueWithIdentifier:#"blurSegue" sender:self];
How can I perform the custom segue and force it to use the view controller I allocated (called VC above)?
https://github.com/AlvaroFranco/AFBlurSegue
I need to instantiate the view controller with properties before I
present the view controller.
Why do you have to instantiate CustomViewController before triggering the segue. That shouldn't be necessary, if you need access to a property of CustomViewController before it's shown, you can set it in prepareForSegue.
Try this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"blurSegue"]) {
CustomViewController *customViewController = (CustomViewController *)segue.destinationViewController;
customViewController.propertyToSet = XXX; // set the property here
}
}
Ah, by the way, instead of
[self.navigationController performSegueWithIdentifier:#"blurSegue" sender:self];
just use:
[self performSegueWithIdentifier:#"blurSegue" sender:self];

[UITabBarController setSports:]: unrecognized selector sent to instance 0x7b80e2b0

I’m building an iOS app. I want pass array value from one view controller to another through segue.
While doing this i’m getting an error:
[UITabBarController setSports:]: unrecognized selector sent to
instance 0x7b80e2b0.
here is my code:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"sportsSelection"]) {
Play *play=[segue destinationViewController];
play.sports=selectedSports;//error break point is here.
//sports and selected sports are NSMutableArray
}
}
To make the situation a bit clearer, you are getting the error because you are trying to call a method (setSports:) on a class that does not implement this method, this is exactly what the error message tells you:
[UITabBarController setSports:]: unrecognized selector sent to
instance 0x7b80e2b0.
Your segue apparently has a UITabBarController as destination, so it's clear that it does not know about the method setSports:, since this one is actually implemented in your custom view controller (apparently called Play?!).
Then, as Eike pointed out in his answer, you need to get Play from the UITabBarController which it is embedded in. That's why he suggested to use: Play* p = ((UITabBarController*)segue.destinationViewController).viewControllers[0];, it means that you should get the view controller at index 0 from your UITabBarController.
According to your comment, the view controller at index 0 is a UINavigationController, which (naturally) also does not respond to setSports:, because just like UITabBarController it is a class provided by Apple and doesn't know about this method.
Now, you need to find out where in this UITabBarController your custom view controller Play is located. Either it is a direct part of UITabBarController and you can find it by using Eike's approach and just modify the index from 0 to n (where n is the number of view controllers that the UITabBarController has hold of), or another option is that it is embedded in the UINavigationController that you received at index 0, so in that case you'd have to access the UINavigationController's view controller stack (e.g. the array property viewControllers or just the one that is currently on top of the stack using topViewController).
Edit: I want to give you some extra information about what's going on in your code, especially related to Eike's answer:
From the information that you gave us in your question and in the commment to Eike's solution, we can assume the following code to be correct:
if ([[segue identifier] isEqualToString:#"sportsSelection"]) {
UITabBarController *tabBarController = [segue destinationViewController]; // the destination of the segue is your `UITabBarController`
UINavigationController *navigationController = tabBarController.viewControllers[0]; // gets the first of the view controllers contained in your UITabBarController
NSLog(#"view controllers in navigation controller: %#; top view controller: %#", navigationController.viewControllers, navigationController.topViewController); // print all view controllers managed by navigationController
}
EDIT 2: From your comment I can now assume the following code to be correct:
if ([[segue identifier] isEqualToString:#"sportsSelection"]) {
UITabBarController *tabBarController = [segue destinationViewController]; // the destination of the segue is your `UITabBarController`
UINavigationController *navigationController = tabBarController.viewControllers[0]; // gets the first of the view controllers contained in your UITabBarController
Play *controller = (Play *)[[navigationController viewControllers] objectAtIndex:0];
controller.sports=selectedSports;
play.sports = selectedSports;
}
You need to setSports: to your view controller not the UITabBarController.
Play* p = ((UITabBarController*)segue.destinationViewController).viewControllers[0];
p.sports = selectedSports;

General way to pass data to UIViewControllers when using a UITabController

I still haven't grasped this transfer with the structure below. I have read many posts, and have seen the same unanswered post by others, but no resolution.
I will try to simplify the question to make it easier for all.
The structure of the project is:
UITabbar with tab1 and tab2
Tab1 has a Nav controller-->ViewController1
Tab2 has a Nav controller -->ViewController2
In viewcontroller1 (tab1) I have object X.
In ViewCOntroller2 (tab2) I want to display object X.
Don't worry about displaying, that's the easy part.
Question: How do you pass object X from tab1 to tab2. (what is the general pattern).
If you want to do it using prepareForSegue, is this ok, or is there a better way.
If using prepareForSegue, where do you drag the segue to?
The tabbarcontroller
OR*****
2. to the second VC
Hopefully this is clear enough. With this in mind how would you perform the transfer?
Using the segue 1:
I tried doing this:
//(From View controller 1)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"CreateObjectXToDisplayObjectX"])
ViewController2* vc2 = [[ViewController2 alloc] init];
UITabBarController* tbc = [segue destinationViewController];
vc2 = (ViewController2 *)[[tbc customizableViewControllers] objectAtIndex:1];
//Crash here with with [MainNavigationControllerDesign setViewController1Delegate:]: unrecognized selector sent to instance 0x1064ef70'
vc2.viewController1Delegate=self;
vc2.objectXAtViewController2 = _objectXFromViewController1;
}
}
So, how is this Object X transfer accomplished?
Thank you in advance
You don't want to use segues in this way. Segues always instantiate new controllers when you go to them, but you already have these controllers embedded in the tab bar controller. If you were setting this up in code, I would say use a delegate, but if you set this up in IB, it's hard to do that. From VC2, you can get a reference to VC1's navigation controller with self.tabBarController.viewControllers[0]. VC1 will be that navigation controller's topViewController, so, putting that together, and adding a cast, you can access VC1 like this:
ViewController1 *vc1 = (ViewController1 *)[self.tabBarController.viewControllers[0] topViewController];
Once you have that reference, you can access any of vc1's properties. Don't forget to import ViewController1.h into ViewController2's .m file.

ios - nav bar on a presented modal controller with storyboard

I simply want to add a navigation bar (with some nav bar button) on a presented modal controller with storyboard.
Programmatically with XIBs, it looks like that :
SDMapController *mapController = [[SDMapController alloc] initWithNibName:#"SDMapController" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:mapController];
[self presentModalViewController:navigationController animated:YES];
But I have no idea how to handle it with Storyboard. I guess i have to implement some code on the -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender method but since the destinationController property of segue object is readonly, i don't really know how to do this.
Any idea ?
You have to implement the prepare for segue, only if you want to pass on some data to your presented view controller. Otherwise you can leave it empty. The presenting of the View Controller is from the Interface Builder. You add a navigation controller with it's root view controller and make a segue (ctrl + drag) to the navigation controller. Set the segue type to modal, and give it an ID. You can trigger this segue from code by calling [self perforSegueWithIdentiefier:#"MySegueID"];. If you dragged the segue from a button or a table view cell, it will be triggered automatically when you tap on it, without calling this method. As I said, in the prepareForSegue method, the segue.destinationViewController will bee the presented navigation controller. You can access it's topViewController if you need and pass some data to it.

Problems with popToRootViewControllerAnimated

In my StoryBoard, I have embedded my root view controller inside a Navigation Controller, and this view gets displayed when the app is launched. The user then goes through a series of views, which are basically view controllers presented modally.
I'm trying to implement a function to go back to the root view controller, so I called
-(IBAction)backToMenu{
NSLog(#"Back to menu");
[self.navigationController popToRootViewControllerAnimated:YES];
}
but nothing happens. If I do NSLog(#"%#", self.navigationController"); it prints null, so I guess that's the source of my problem. You can't call popToRootViewControllerAnimated: on a view controller that's been presented modally.
Unless you pass a reference to the root view controller. But is this the right approach? If so, how do you pass a reference to the root view controller? As all my view controllers are instances of a custom subclass of UIViewController, I tried doing inserting this in said class's code :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
[[segue destinationViewController] navigationController] = [[segue sourceViewController] navigationController];
}
but I get an error saying that navigationController is not assignable.
Any thoughts?
In the documentation for dismissViewControllerAnimated:completion:, it says:
If you present several view controllers in succession, thus building a
stack of presented view controllers, calling this method on a view
controller lower in the stack dismisses its immediate child view
controller and all view controllers above that child on the stack.
This suggests that you should keep a reference to your root view controller (or otherwise notify it) and call this method on it. (There's a similar note on the deprecated dismissModalViewControllerAnimated: in case you're using that.)
Does the class that implements the method -(IBAction)backToMenu inherit from UIViewController? I get thi skind of error when the class where I'm implementing the popToRootViewControllerAnimated inherits from some other class. To hold a reference to the original navigatorController I would:
Declare in the class where backToMenu is implemented, a pointer to a pointer to the navigation controller, something like: UINavigationController *navCon; yo should declare this as a property and then synthesizeit.
So when you instance the ViewController for this class you can do something like:
TheClassViewController *theClassVC = [TheClassViewController alloc] initWithNib:#"TheClassViewController" bundle:nil];
theClassVC.navCon = self.navigationController; // Here is where you pass THE reference
[self.navigationController pushViewController:theClassVC animated:YES];
Just solved it.
The problem was that, in the StoryBoard, the initial view controller was the root view controller and not the Navigation Controller it was embedded in!
Once you set the Navigation Controller as the initial view controller (i.e. drag the arrow so that it points to it), popToRootViewControllerAnimated works like a charm.

Resources