Passing data between controllers gives an error due to complicated segue - ios

I have a modal segue which goes from a view controller to a tab bar controller which is embedded in a table view as you can see from this screenshot:
I want to pass data between the login screen and the table view. I use the following code:
-(IBAction)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"Enter App"]){
//Pass on username so that app can set everything up for that specific user
GamesListTableViewController *gamesList = (GamesListTableViewController *)segue.destinationViewController;
if ([segue.destinationViewController isKindOfClass:[GamesListTableViewController class]]) {
NSLog(#"ENTERING PROPER CLASS");
}
else{
NSLog(#"ENTERING WRONG CLASS");
}
gamesList.userID = self.userID;
}
}
My app crashes due to the last line of code. And i checked why (as you can see in the code above) and the reason is that the segue destination is not the GamesListTableViewController, but what i am assuming is the tab bar controller. How to i work around this problem?

UITabbarController *tabController = (UITabbarController*) segue.destinationViewController;
UINavigationController *nav = (UINavigationController*) tabController.viewControllers[0]; // or some other nr
GamesListTableViewController *tvc = nav.topViewController;

Related

EXC_BAD_ACCESS crash upon dismissing UIViewController

I have two buttons triggering segues to two different UIViewCOntrollers, using this code:
- (IBAction)newTransButton:(UIButton *)sender
{
[self performSegueWithIdentifier:#"newTransSegue" sender:self];
}
- (IBAction)switchAccountButton:(UIButton *)sender
{
[self performSegueWithIdentifier:#"selectAccountSegue" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
if ([[segue identifier] isEqualToString:#"newTransSegue"])
{
UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
AddTransactionVC *atvc = (AddTransactionVC *)navController.topViewController;
atvc.delegate = self;
WMMGTransaction *addedTransaction = (WMMGTransaction *)[WMMGTransaction MR_createInContext:localContext];
addedTransaction.account = self.currentAccount.name;
atvc.thisTransaction = addedTransaction;
}
else if ([[segue identifier] isEqualToString:#"selectAccountSegue"])
{
UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
AccountSelectVC *acctSelVC = (AccountSelectVC *)navController.topViewController;
acctSelVC.delegate = self;
}
}
Activation of either button segues to the appropriate view controller, but causes this warning:
Warning: Attempt to present <UINavigationController: 0x7fb99b4dd430> on <FirstViewController: 0x7fb99b565dd0> whose view is not in the window hierarchy!
I have a Save and a Cancel Navigation bar button on each View controller. Other than as mentioned above, everything works as expected, except for the Cancel button on the View controller at newTransSegue, which dismisses the VC, but crashes the app with this error:
EXC_BAD_ACCESS (code = 1, address = 0x7f87394af29)
Here is the delegate method I use to dismiss that VC:
-(void)addTransactionViewControllerDidCancel
{
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
I've been at this for a couple of days, and have tried deleting the segues and recreating them in storyboard, as well as doing the same for the navigation controllers. I've gone off the rails somewhere, but can't see exactly where.
I could sure use some guidance. :)
OK, I studied the reference kindly provided by #Jay. Turns out I had seen it before, but only Part 1. In Part 2, I discovered a reference to Enable Zombie Objects, which I did. Now, when the app crashed, I was provided with this message: [_UILayoutGuide isDescendantOfView:], which pointed to an issue in the Storyboard.
Upon examining the Storyboard, I discovered that, surprisingly, the representation of the view controller in question was shaped differently than the surrounding view controllers. I wish I'd made a screenshot, but in the heat of the hunt, I didn't.
In any case, further research turned up this question (and its associated comments). My investigation revealed that, while I had Size Classes enabled, for some reason I can't explain, the size of the relevant View Controller under Simulated Metrics had been set to "Freeform." I reset it to "Inferred" and things appear to be operating normally now--no crashes. Wish I could explain it in detail, but I'm happy with the result!

Protocols with Navigation Controller

I have a project where I have set up a protocol to pass information back from one TableViewController to a ViewController. Everything worked fine and as expected, but I decided to embed in a Navigation Controller to the TableViewController so I could add a "DONE" barButtonItem to dismiss the Controller when the user is done. Since embedding in the navigation controller, the button works well, the TablieViewController looks identical, but none of its features and methods that use the Protocol and Delegate work, and if I remove the NavigationController everything works. Could someone explain how I can fix this issue? I am fairly new to iOS and objective c.
Here is the prepareForSegue method in the NoteViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.destinationViewController isKindOfClass:[ToolTableViewController class]]) {
ToolTableViewController *targetVC = segue.destinationViewController;
targetVC.toolDelegate = self;
targetVC.autoCorrectIsOn = self.autoCorrectIsOn;
targetVC.undoAvailable = self.undoAvailable;
targetVC.redoAvailable = self.redoAvailable;
}
}
ToolTableViewController.h
#protocol ToolTableViewControllerDelegate <NSObject>
#property (weak, nonatomic) id <ToolTableViewControllerDelegate> toolDelegate;
ToolTableViewController.m - example of a method called
-(void)clearInputText{
// NSLog(#"Clear Method Selected");
[self.toolDelegate didClearInputText];
}
NoteViewController.m
-(void)didClearInputText{
self.noteTextView.text = #"";
[self dismissViewControllerAnimated:YES completion:nil];
}
Since your table view controller is embedded in a navigation controller, it's the navigation controller that will be the destination view controller of the segue. Also, it would be better to use the identifier of the segue for the if statement, rather than the class of the destination view controller (I'm using "SegueToTable" as the identifier, change that to whatever you put for the identifier). Therefore, prepareForSegue should look like this,
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"SegueToTable"]) {
UINavigationController *nav = segue.destinationViewController;
ToolTableViewController *targetVC = nav.topViewController;
targetVC.toolDelegate = self;
targetVC.autoCorrectIsOn = self.autoCorrectIsOn;
targetVC.undoAvailable = self.undoAvailable;
targetVC.redoAvailable = self.redoAvailable;
}
}
Your delegate methods are called just fine (based on the sample you pasted).
Since your controllers are embedded in a navigation controller now, you should use:
[self.navigationController popViewControllerAnimated:YES]
Before, you were presenting your controllers modally, that's why dismissViewController worked fine then but not now ( in the context of a nav controller).

Segue issue with SWRevealViewController

I'm trying to segue from side menu page of SWRevealViewController and transfer data to another view controller. It is crashing and I'm getting this issue ` -[UINavigationController setStr1:]: unrecognised selector sent to instance 0x7f8c92224c80 '
while I'm using Reveal View Controller Push Controller method to push to the other view controller.
On the other hand in other view controllers I'm using SHOW instead of SWRevealViewControllerSeguePushController and it is working fine not crashing. I'm using storyboard.
Please where would be my issue?
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"TESTTEST"]) {
ViewController *destViewController = segue.destinationViewController;
destViewController.str1 = #"data pass";
}
}
The error indicates that the segue destination view controller is a navigation controller (which consequently doesn't respond to the setStr1 selector). So it looks like your ViewController is embedded in a navigation controller in the storyboard. If so, change your code as follows:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"TESTTEST"]) {
UINavigationController *navigationController = segue.destinationViewController;
ViewController *destViewController = navigationController.topViewController;
destViewController.str1 = #"data pass";
}
}

App crashes after embedding in navigation controller

!(http://s10.postimg.org/8gy1q2rrt/question.png)
When i get to the last view controller on the right and press BACK button I Go back to the 1st controller not the second , i want to go back 1 step. (1>2>3). so i added navigation controller between them (don't know why ) , and app crashes when I want to go to the 3rd viewcontroller . all segues are PUSH.
This is BUTTON #1 CODE. #"tevzeulimenu" is the ID of the tabbarcontroller.
- (IBAction)goMenu1:(id)sender {
UITabBarController *firstView = [self.storyboard
instantiateViewControllerWithIdentifier:#"tevzeulimenu"];
[self.navigationController pushViewController:firstView animated:YES];
}
And this is code for segue:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"show1"])
{
DetailMenuViewController *detailViewController =
[segue destinationViewController];
NSIndexPath *myIndexPath = [self.tab1
indexPathForSelectedRow];
long row = [myIndexPath row];
detailViewController.detailMenu= #[_menu1Images[row],
_menu1Names[row],
_menu1Prices[row],
_menu1Text[row]];
}
}
Help to solve this problem. I want to go back from the 3rd view controller on the right(the last one) to 2nd when pressing back and not to the 1st.
You should use :
- (IBAction)goMenu1:(id)sender {
[self performSegueWithIdentifier:#"show1" sender:self];
}
Of course you have to add a Segue in your storyboard with the identifier : show1.
Hope that will help.
EDIT: In the context.

How to push from view controller to navigation view controller using prepareForSegue method?

I have a project which has a view controller as initial screen and then a view controller embedded inside a navigational view controller. I also have a button on first screen on click of which I want the navigational controller screen to be opened.
I clicked on button and then on ' connections inspector', I added push event to that navigational controller, but segue is not happening. How could I achieve it please?
SOLUTION
Finally after a bit of research I managed to get this thing working. Here is the code i am using:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Source Controller = %#", [segue sourceViewController]);
NSLog(#"Destination Controller = %#", [segue destinationViewController]);
NSLog(#"Segue Identifier = %#", [segue identifier]);
if ([segue.identifier isEqualToString:#"mysegue"])
{
NSLog(#"coming here");
SecondViewController *loginViewController = (SecondViewController *)segue.destinationViewController;
//SecondViewController *navigationController = [[UINavigationController alloc]init];
[self presentModalViewController:loginViewController animated:YES];
}
}
Are you sure that the Navigation Controller's connection to the embedded view controller is set up correctly? The first view controller should be connected to the Navigation Controller, with a Push style segue, and the navigation controller should be connected to the second view controller, with a Relationship style segue.
At any rate, one of the official Apple tutorials does just this, so you might be able to compare your code to it and see if there's a difference: Your Second iOS App. The prepareForSegue method itself isn't really involved with firing the segue; it is just invoked before the segue runs to prepare the new view controller.

Resources