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

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;

Related

ios/xcode/objective-c: Segue to modal view controller embedded in navigation controller

I have a segue from a button in a detail view controller to a new modal view controller that displays a map.
To pass the location to display on the map, I use preparetosegue as follows:
if ([segue.identifier isEqualToString:#"showMap"]) {
IDMapView *destViewController = segue.destinationViewController;
destViewController.contact=_contact;
}
However, I after embedding the modal view controller in a navigation controller to implement a cancel button, the app is now crashing when I click on the button giving the error in the log:
[UINavigationController setContact:]: unrecognized selector sent to instance 0x7f8738ea5ce0
(lldb)
The error seems to have something to do with the navigation controller not having the property contact (which is on the view controller.)
Can anyone suggest the right way to do this?
The destinationViewController is now a UINavigationController and not an IDMapView. You need to get the topViewController from the UINavigationController.
if ([segue.identifier isEqualToString:#"showMap"]) {
UINavigationController *navigationController = segue.destinationViewController;
IDMapView *destViewController = navigationController.topViewController;
destViewController.contact=_contact;
}

If I have a container view in the Storyboard, is it possible to have only ONE of the view controllers be embedded in a navigation controller?

See the following setup in my Storyboard:
I've got two container views in the first view controller, one for the main view that displays posts, and the other for a menu that the posts view slides out to reveal.
I'd like the menu bar to slide away like described here, which I have working but without the navigation bar. I've tried using Editor > Embed in Navigation Controller to both the view controller that contains the children (which worked, but when the menu slid out it still showed for the menu which doesn't look as intended) and when I just do it for the posts view controller it crashes with this error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UINavigationController setContainingViewController:]: unrecognized selector sent to instance 0x8e81c60'
Does anyone know how to accomplish this effect?
I assume this post is related to this one by Doug Smith, Why does hiding my status bar completely break my simple animation?. Your problem doesn't have anything to do with only one of the controllers being embedded in a navigation controller. It crashes, because you're trying to call setContainingViewController on a UINavigationController instead of the PostsViewController, which was (before you added the navigation controller) the destinationViewController of the embed segue. Since the navigation controller is now the destinationViewController, you need to change the code in prepareForSegue to this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Posts"]) {
UINavigationController *nav = (UINavigationController *)segue.destinationViewController;
PostsViewController *postsViewController = (PostsViewController *)nav.topViewController;
postsViewController.containingViewController = self;
}
if ([segue.identifier isEqualToString:#"Menu"]) {
MenuViewController *menuViewController = (MenuViewController *)segue.destinationViewController;
menuViewController.containingViewController = self;
}
}

pass data to view controller using storyboard segue iOS

I know there are lots of postings about this but I have tried everything and nothing has worked. So I have tried to pass an object between two view controllers, to a DBKIngredientsViewController embedded in a navigation item. I have a push segue with the identifier "showIngredientsSegue" to the DBKIngredientsViewController. The error message I receive is:
'NSInvalidArgumentException', reason: '-[DBKIngredientsViewController topViewController]: unrecognized selector sent to instance 0x8a92450'
The view controller to which I am segueing is embedded in a navigation controller, which I think is messing it up. What's the way around this? To be clear, the DBKViewController is already embedded in a navigation controller, and the push segue pushes the DBKViewController, not the navigation controller embedding it. I have tried it different ways but none seem to work.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showIngredientsSegue"]){
UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
DBKIngredientsViewController *controller = (DBKIngredientsViewController *)navController.topViewController;
controller.targetRecipe = selectedRecipe;
}
}
Are you sure that segue.destinationViewController is a UINavigationController? It seems like it's just a DBKIngredientsViewController so this should work:
DBKIngredientsViewController *controller = (DBKIngredientsViewController *)segue.destinationViewController
Also if DBKViewController already has a navigation controller then you do not need a second one if you are pushing DBKIngredientsViewController. You would only need a second one if you are modally displaying DBKIngredientsViewController.

Passing data from a View to another view inside a tabcontroller

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]

prepareForSegue and delegates

I have an application with two segues. In one of the segues, the current view controller becomes a delegate and the other does not.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"MoreOptions"]) {
UINavigationController *navigationController = segue.destinationViewController;
MoreOptionsViewController *controller = (MoreOptionsViewController *)navigationController.topViewController;
controller.delegate = self;
} else if ([segue.identifier isEqualToString:#"FullStoryView"]) {
SingleStoryViewController *detailViewController = segue.destinationViewController;
detailViewController.urlObject = sender;
}
}
All of this is working fine, but I would like to try and understand the code better. What I don't understand is that I have to get a reference to the MoreOptionsViewController by grabbing it from navigationController.topViewController rather than simply getting it from segue.destinationViewController like I do in the second if condition. Is it because I'm setting the current view controller (self) as the delegate? Again, I'm not trying to solve a problem, just trying to get a better understanding of what's going on.
Take a look at your storyboard and it should be evident why this is the case. You have embedded MoreOptionsViewController in a UINavigationController and connected a segue to the navigation controller, thus making it the destinationViewController. This is fairly common.
The delegate is largely irrelevant in the context of your question.
Your first segue's destination is a navigation controller, which contains the view controller you are really interested in. Therefore to get to that view, you need to go through the navigation controller since that won't have any properties you are interested in setting.
Your second segue goes directly to a single view controller, so you can access it directly.

Resources