Ok so I have a view controller with a button. When that button is pressed I have another view controller that will be presented modally. I would like to embed that view controller in a navigation controller, but this can't be done programmatically, the navigation controller needs to be in the xib.
In my xib I have two objects: the navigation controller, and a view object that has all of my view controllers content. The navigations controller's view controller has its view property set to my view object.
My issue is that in my parent view controller I am trying to present the modal with this code
self.modalController = modalController.new;
self.modalController.delegate = self;
[self presentViewController:self.modalController animated:YES completion:NULL];
And then I get this crash:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modally an active controller <ParentController: 0xXXXXXXXX>.'
This just baffles me and I can't seem to figure out how to get passed it. I understand that this is achievable via programmatically setting up a navigation controller but I cannot use that route for this problem. Any ideas?
I have not been able to successfully instantiate any UIViewController class (or subclass) from a xib file. The only reason those object are there in Interface Builder is for use in Storyboards. You will have to figure out a way to do it in code. You can always create the UIView in a xib and then set the view of a view controller to the view loaded from a xib. There's a couple different ways to do that...
NSString *aNibName = #"customNibName";
MyViewController* myViewController = [[MyViewController alloc] initWithNibName:aNibName bundle:nil];
[navigationController pushViewController:myViewController];
Make sure to set File's Owner of the View created in Interface Builder to the UIViewController subclass.
Related
Ok, first let's name things:
I have a table view in my root view controller wich we'll call "HomeViewController". In that table view each cell tap will push a different view controller. This collection of view controllers we'll call "DetailViewControllers".
I am perfecly aware that I can make this work by simply loading and pushing each of the DetailViewControllers programmatically inside the didSelectRowAtIndexPath method. I want to do something different instead using storyboard and a prototype cell and I'm not succeeding, so I'm looking for some advice since I'm not too well versed in storyboards and segues.
The behavior I'm trying to achieve here is:
I'll have a segue from a prototype cell in the table view in my HomeViewController. That segue pushes a "base" view controller, from which every DetailViewController inherits. These view controllers don't have an assigned view controller in the storyboard either.
In the prepareForSegue method I want to cast the 'destinationViewController' to the 'right' class. The app crashes at that point saying it "Could not cast value of type 'BaseTestViewController' to 'TestViewController'.". Which is totally understandable.
So, my question is: is there a way to make a segue work like that?
You can't create segues programatically. Segues don't exist without a storyboard. You can just push to a view controller via loading a nib file.
Here's how you do it.
Let's say you have a nib file containing the layout of the view for the main view of your view controller. We'll name it "Test" for instance.
Go to that nib file, click file's owner.
Change class to the name of your view controller. In my case, I named it ViewController.
Right click on file's owner. Link the outlet of view of your view controller to the view in the nib file.
Then in the view controller where you want to transition to that view controller, you do it like this:
UIViewController *controller = [[UIViewController alloc] initWithNibName:#"Test" bundle:[NSBundle mainBundle]];
[self presentViewController:controller animated:YES completion:nil];
It will present the view controller modally.
If you are embedding a navigation controller then you can do it like this:
[self.navigationController pushViewController:controller animated:YES];
Hope it helps.
Try like this without storyboard segue.
let objDestVC = self.storyboard.instantiateViewControllerWithIdentifier("DestVCStroyboardId") as! DestinationViewController
self.navigationController?.pushViewController(objDestVC, animated: true)
Please see the following attached image for more understanding.
The scenario is : I have five view controllers
Each view navigate to next viewController on push
Now the MidContainerViewController has got the Container which embeds the FirstViewController.
Bottom of MidContainerViewController is a static view which should not change while navigating further.
On navigation The FirstViewController should be of size equal to container
Also when I navigate to SecondViewController from FirstViewController, it should also be of size of Container.
Objective 1 : 'FirstViewController' and 'SecondViewController' should not take whole screen overlapping the bottomView image on MidContainerViewController.
Objective 2 : I must pop to root "View Controller" on last 'push' on SecondViewController.
Solutions :
1) Currently As I have embedding the root "View Controller" to navigationController. No problem with objective 2. It successfully navigates back to root. But can't achieve objective 1
2) If I embed the "First View Controller" too with navigationController the objective 1 is achieved but start facing problem for objective 2. It pop back till 'MidContainerViewController' only.
Any suggestion are highly appreciated.
Thanks,
Assuming your are manually handling push/pop events without using storyboard, I recommend you to not push the FirstViewController from MidContainerViewController. Add the next view controller as child view controller through following code:
FirstViewController *firstViewController = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:[NSBundle mainBundle]];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
[self addChildViewController:navController];
[navController.view setFrame:CGRectMake(0.0f, 0.0f, _containerView.frame.size.width, _containerView.frame.size.height)];
[_containerView addSubview:navController.view];
[navController didMoveToParentViewController:self];
From the above code you'll achieve your first objective. In the above code, the FirstViewController gets initiated on its own separate navigation controller object, so it will have different navigation stack. So if you further push and pop from FirstViewController & SecondViewController, your view will not take the whole screen. But if you call popToRootViewController from last view controller, your root view controller would be FirstViewController in that specific container view.
To achieve second objective, you'll have to create a public property to contain reference of main navigation controller object in your AppDelegate class. Create your root view controller from that navigation controller object. In your last view controller, you'll then have to get reference of that navigation controller property from your AppDelagate class and then call popToRootViewController from that object.
i think you must present your root view controller from the secondView Controller rather that embedding to root view controller.
Thank you everyone.
The problem is solved and both the objectives are achieved.
I kept only one navigation controller as root view controller.
I created one customContainerViewController.
This class has instances of all the children it is supposed to show.
This class acts as delegate for each of its childViewController. Make customContainerViewController as deleagte of each childViewController.
I updated the chilren using delegation method and using UIView transition method in UIKit.
This worked for me.
I'm currently trying to use push segue to navigate between two views. This works fine elsewhere in my app, no problems. However, in this particular location, I'm presented with the following error:
Terminating app due to uncaught exception 'NSGenericException',
reason: 'Push segues can only be used when the source controller is
managed by an instance of UINavigationController.
Now here's the thing, i know exactly what this error means, and exactly how to fix it.
Editor -> Embed in -> Navigation Controller on the view controller i'm trying to push from.
The thing is, I've done that already and the error persists. Any ideas?
For what it's worth, the navigation bar doesn't even appear in the view that was embedded inside the nav controller.
Here is the current setup
I have a ViewController on the storyboard that is setup to inherit from UIViewController. That controller is embedded inside a UINavigation controller via the above method.
On this view controller view, there are two buttons. Inside IB I have dragged a push segue from each of those buttons to the respective view controllers I would like to present.
I've also tried doing the segue in code via the following:
- (IBAction)btnTerms:(id)sender {
UIViewController *termsVC = [STORYBOARD instantiateViewControllerWithIdentifier:#"TermsOfServicesViewController"];
[self.navigationController pushViewController:termsVC animated:YES];
}
In the above case, nothing happens at all. No crashes or anything. Debugger breakpoints confirm that the method is being hit, though.
Update as per Phillip's question
UINavigationController *nav = self.navigationController;
[self.navigationController pushViewController:termsVC animated:YES];
- (IBAction) btnSignUpCLicked:(UIButton *)sender {
[self presentViewController:[STORYBOARD instantiateViewControllerWithIdentifier:#"SignUpViewController"] animated:YES completion:nil];
}
From the comments:
Embedding a view controller inside a navigation controller will cause the embedded controller to load when its navigation controller does. The reverse is not implied (, which is reasonable because there might be a case where the embedded controller would be also useful standalone).
I perform some data loading tasks from an Ojective§C class and once everything is loaded, I simply wants to display a Viewcontroller subclass prepared in a storyboard.
So when everything is ok, the following method is called:
- (void)loadingNextView
{
CABBndGSite *mySite = [CABBndGSite alloc];
CABBndGSelectLanguageViewController *vc = [[mySite myRootViewController].storyboard instantiateViewControllerWithIdentifier:#"SelectLanguageViewController"];
[[mySite myRootViewController] presentViewController:vc animated:YES completion:nil];
}
So I verified that myRootViewController is not nil. It's a UINavigationController class.
vc is not nil so it found my view in the storyboard.
Anyway, the presentViewcontroller message seems to doing what expected.
Certainly a stupid mistake but my poor iOS programming knowledge lets me in the fog!
I use this code from ViewController subclasses with success and as here I get a valid ViewController pointer, I don't understand why it doesn't work.
I also tried to implement the AppDelegate method explained here How to launch a ViewController from a Non ViewController class? but I get a nil navigation pointer. Maybe something not well connected in my application
May I have some explanation?
Kind regards,
UINavigationController maintains a stack of view controllers. You can access this stack through the viewControllers property. To present your view controller, you can:
(a) have the navigation controller push the new view controller on to
the stack (pushViewController:animated:);
(b) have the top view controller in the view controller stack present
the new view controller modally (presentViewController:animated:completion:), or;
(c) add the new view controller to the view controller stack array
manually by assigning a new viewControllers array to the navigation
controller's viewControllers property (setViewControllers:).
I'm running into trouble with what I think is a pretty basic task. Within peoplePickerNavigationController:peoplePicker:shouldContinueAfterSelectingPerson: i want to show my own view rather than the standard person view. I'm using a Storyboard, but don't think I can simply manually segue to a window here so I'm thinking I need to create a new XIB with a View Controller in it. I'm setting the Class of the View Controller to my custom View Controller in IB. Then in peoplePickerNavigationController:peoplePicker:shouldContinueAfterSelectingPerson: I'm doing:
MyVC *myVC = [[MyVc alloc] initWithNibName:#"XIBFileName" bundle:nil];
[self presentModalViewController:myVC animated:YES];
In my View Controller initWithNibName gets called, but not viewDidLoad. What am I doing wrong here?
Just try [peoplePickerVC presentModalViewController:myVC] instead of presenting from self.
The issue is that the peoplepickerviewcontroller will be in the top of the navigation stack. Becuase you wud've presented the peoplepicker from self. As this is the case, you wont be able to present/push from self as its not at the top of the navigation stack.
Otherwise once the peoplepicker has been poped, then you can further present from self.