iOS - NavigationController thinks it's getting the same controller pushed twice - ios

I'm a bit confused about the following code. If I comment out the second statement, it successfully shows the view:
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
delegate.navController.viewControllers = [NSArray arrayWithObject:aViewController];
[delegate.navController pushViewController:aViewController animated:YES];
[aViewController release];
Otherwise, it crashes on the following:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Pushing the same view controller instance more than once is not supported
I add a different view controller in the app delegate, but not this one. What could be making it think it's the same one?

delegate.navController.viewControllers = [NSArray arrayWithObject:aViewController];
[delegate.navController pushViewController:aViewController animated:YES];
First line set's aViewController as navController's only controller. Second line pushes aViewController to navController again so yeah, no wonder you get it twice. Depending on what you want to do, ditch one of those two lines.
If you want to set aViewController as only controller on navController, keep first line.
If you want to push aViewController as a new controller on navController, keep second line.

Related

Issues with rootViewController and Home Screen Quick Actions

I have the below Objective-C code to launch my app with Home Screen Quick Actions:
- (void)applyShortcutItem:(UIApplicationShortcutItem *)shortcutItem
{
ViewController *rootViewController = (ViewController *)[self.window rootViewController];
NSLog(#"Here %# - %#", rootViewController, shortcutItem);
if([shortcutItem.type isEqualToString:#"LaunchMode0"])
{
[rootViewController setShortcutAction:LaunchMode0];
}
else if([shortcutItem.type isEqualToString:#"LaunchMode1"])
{
[rootViewController setShortcutAction:LaunchMode1];
}
}
However, I keep getting runtime errors (unrecognized selected sent to instance) when I try to launch with the quick actions. Notably, it's these two lines where the app seems to trip up:
[rootViewController setShortcutAction:LaunchMode0]; and [rootViewController setShortcutAction:LaunchMode1];
It doesn't seem to like the rootViewController. Technically, the initial View Controller is the Navigation Controller, however the app launches to my main view controller (the app only has two views, the main one, and an about page).
There is more code above that code in my project, but this is the part that's giving me the error-- but let me know if seeing the other code would help (I didn't want the post to be too code heavy).
Thanks so much!
EDIT: as requested, here is the complete NSLog.
2019-09-23 18:18:01.317271-0400 AppName[1719:200993] Here <UINavigationController: 0x108802200> - <UIApplicationShortcutItem: 0x282bd1500; type: Mode1Shortcut, title: Mode 1>
2019-09-23 18:18:01.321819-0400 AppName[1719:200993] -[UINavigationController setShortcutAction:]: unrecognized selector sent to instance 0x108802200
2019-09-23 18:18:01.323462-0400 AppName[1719:200993] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UINavigationController setShortcutAction:]: unrecognized selector sent to instance 0x108802200'
*** First throw call stack:
(0x2045aa98c 0x2037839f8 0x2044c71c8 0x231033220 0x2045b01d4 0x2045b1e6c 0x102c14af0 0x102c148ec 0x230ffdf90 0x2308cc468 0x2308cd150 0x2308cc224 0x2308d0f24 0x230c012b0 0x206f275d8 0x102fecc78 0x102ff0840 0x206f61040 0x206f60cdc 0x206f61294 0x20453c728 0x20453c6a8 0x20453bf90 0x204536ecc 0x2045367c0 0x20673779c 0x231007c38 0x102c076d0 0x203ffa8e0)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
The problem is this:
ViewController *rootViewController = (ViewController *)[self.window rootViewController];
But you have stated that the root view controller is a UINavigationController. You need to get your ViewController from the nav controller.
UINavigationController *rootViewController = (UINavigationController *)self.window.rootViewController;
ViewController *viewController = (ViewController *)rootViewController.topViewController;
Then update the rest of the code to work on viewController.

Unrecognized selector sent

I have 1 View Controller and 1 Tab Bar Controller with 2 Navegation Controller.
In my simple View I have one form and then when I click in button "Login" I want to load the first View in my Tab Bar Controller.
With this code works perfect:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
Inicial *telaInicial = [storyboard instantiateViewControllerWithIdentifier:#"tabBar"];
[self presentViewController:telaInicial animated:YES completion:nil];
But I want to send and value to this View "Inicial" and I put this:
telaInicial.email = email.text;
But I got this error message:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITabBarController setEmail:]: unrecognized selector sent to instance 0x9fdc8f0'
The object telaInicial that you think is an instance of Inicial is actually a UITabBarController therefore you cannot set the email property on it as it doesn't exist.
I think you want something like this...
UITabBarController *tabBarController = [self.storyboard instantiateViewControllerWithIdentifier:#"tabBar"];
UINavigationController *navController = tabBarController.viewControllers[0];
Inicial *telaInicial = navController.topViewController;
telaInicial.email = // blah
It means that there isn't a setEmail method for the telaInicial object. Is that an instance of a subclass you've written? If so, you might be getting the error because you haven't written a setEmail method for it or because you haven't declared the instance variable email as an #property, in which case the setter and getter methods for it would be synthesized automatically by XCode (prior to XCode 4.something, I think you need to synthesize your properties explicitly - after that version, they're automatic).
Try to write class, that will store your data.
You can access to it from AppDelegate (not really good solution, but very fast).

Use PKRevealController (Slide Menu) on existing project

Before anything and everything, I know there exists a similar thread by another user, I tried the code answered in that but it didnt worked for me as my VCs and storyboard is a bit different, thus asking same question with my setup and parameters
My storyboard and app looks like this, my initial rootViewController as a tabBarController.
I am using this PKRevealController to add a slider left menu bar
https://github.com/pkluz/PKRevealController/blob/master/Documentation/USAGE.md
I added the following code (taken from the answer on similar question I found on SO) to my appDelegate's didFinishLaunchingWithOptions method
PKRevealController *revealController = (PKRevealController *)self.window.rootViewController;
UIViewController *leftViewController = [[GDmenuViewController alloc] init];
UIViewController *frontViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"tabBarCtrl"];
[revealController setLeftViewController:leftViewController];
[revealController setFrontViewController:frontViewController];
GDmenuViewController is the UITableViewController class I made for my UITableView menu to use on left
tabBarCtrl is the StoryBoardID for the tabBarController I set
Upon compilation I am getting the following error
2014-03-16 18:18:06.659[3595:70b] -[UITabBarController setLeftViewController:]: unrecognized selector sent to instance 0xcf565a0
2014-03-16 18:18:06.662[3595:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITabBarController setLeftViewController:]: unrecognized selector sent to instance 0xcf565a0'
--------Update-------------
I changed the code in app delegate to the following since my tabBarController was my initialVC
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
GDmenuViewController *leftViewController = [tabBarController.storyboard instantiateViewControllerWithIdentifier:#"leftMenu"];
PKRevealController *revealController = [PKRevealController revealControllerWithFrontViewController:tabBarController leftViewController:leftViewController];
self.window.rootViewController = revealController;
Now I am not getting that error but still my menuViewController (TableView) isnt showing up.
I can run the app and even slide to see that the PKVC is working but instead of my tableView, it just shows up a gray blank View
For anyone who comes up across similar problem, here is how I fixed and made it to work :
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
GDmenuViewController *leftViewController = [tabBarController.storyboard instantiateViewControllerWithIdentifier:#"leftMenu"];
PKRevealController *revealController = [PKRevealController revealControllerWithFrontViewController:tabBarController rightViewController:leftViewController];
self.window.rootViewController = revealController;
my TabBarController is my rootViewController as well as the entry point
my leftMenu is the swipe menu TableViewController with a custom class GDmenuViewController
PS: If the swipe works but you dont see your swiped menuVC as expected (grey in my case), check every thing in identityInspector of your menuVC, most probably problem will be there.
In my case, my cells (static) were buggy, so I had to delete all cells and readd them.

crash passing parameter from one viewcontroller to another

I'm trying to pass parameter from one view controller to another, but application crashes with exception.
My code is this:
SelectedItemViewController *nextView = [storyboard instantiateViewControllerWithIdentifier:#"SelectedItemViewID"];
nextView.m_selectedItemId = [NSNumber numberWithInt:777];
[self presentViewController:nextView animated:YES completion:NULL];
And I have the following in my stack:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UINavigationController setM_selectedItemId:]: unrecognized selector sent to instance 0x9c765d0'
In your storyboard, the view controller with identifier SelectedItemViewID is a navigation controller, not a SelectedItemViewController. So, before you set m_selectedItemId you should access the navigation controllers root view controller (which should be your SelectedItemViewController).
I found solution here: instantiateViewControllerWithIdentifier and pass data
What should be done in case if you want to pass parameter to view controller via navigation controller:
UINavigationController *navigationController = [storyboard instantiateViewControllerWithIdentifier:#"SelectedItemViewID"];
SelectedItemViewController *nextView = navigationController.viewControllers[0];
nextView.m_selectedItemId = [NSNumber numberWithInt:777];
[self presentViewController:navigationController animated:YES completion:NULL];
When you select the view controller in your storyboard, is the class set to SelectedItemViewController?
Obviously you seem to have a #property ... m_selectedItemId (or at least setter method setM_selectedItemId) on SelectedItemViewController, otherwise your code wouldn't even compile. But it seems that [storyboard instantiateViewControllerWithIdentifier:#"SelectedItemViewID"] doesn't really return the expected SelectedItemViewController. Hence I have the feeling that you forgot to set the correct class name to SelectedItemViewController in your storyboard.

ios: manage some viewcontroller in navigation controller

In my app I need to manage a navigation controller and move it in these viewcontrollers, so I do it
UINavigationController *navController = (UINavigationController*) [self.storyboard instantiateViewControllerWithIdentifier:#"navigationcontroller"];
[navController addChildViewController:firstViewController];
[navController addChildViewController:secondViewController];
[navController addChildViewController:thirdViewController];
[navController addChildViewController:fourthViewController];
[self presentViewController:navController animated:YES completion:nil];
first problem: navigation open at first fourthviewcontroller, why?
second problem: if from secondviewcontroller i do it to pass at first:
[[self navigationController] pushViewController:self.navigationController.viewControllers[0] animated:NO];
I have a crash that say:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Pushing the same view controller instance more than once is not supported
why? can you help me?
First question
Every time you use "addChildViewController:", the new controller is added at the top of the stack. The last one inserted, your fourthViewController, is at the top of the stack, so it is shown when you call the method
[self presentViewController:navController animated:YES completion:nil];
Second question
It depends on the pushViewController: method itself. In the Apple documentation the doc said that:
The viewController added cannot be an instance of tab bar controller and it must not already be on the navigation stack.
Your app crashes because self.navigationController.viewControllers[0] is already on navigation stack.
First Problem
You're pushing four view controllers onto the navigation stack. So, your stack, after each step, looks like this:
[navController addChildViewController:firstViewController];
Stack: firstViewController
[navController addChildViewController:secondViewController];
Stack: secondViewController, firstViewController
[navController addChildViewController:thirdViewController];
Stack: thirdViewController, secondViewController, firstViewController
You can see the pattern here. In other words, the fourthViewController is presented because it's on the top of the stack.
Second Problem
As for your second problem, you can't push a view controller onto the stack that already exists in the stack. [[self navigationController] pushViewController:self.navigationController.viewControllers[0] animated:NO]; seems absurd when you consider that fact. You're trying to push something from within the stack to the stack.

Resources