Present a view controller from a container view - ios

I had built a UIViewController with a container a view that embeds another UIViewController(I will call it subViewController).
I want the subViewController to present anther instance of it self within its container view canvas (not for all screen).
I tried this using prepareForSegue method
with this method
-(void)showFurtherReadingDetails
{
[self performSegueWithIdentifier:#"ShowArticleDetails" sender:self];
}
Note : the showFurtherReadingDetails method is a delegate method for subVC over, initialized in the supperVC .
but I faced this issue:
'NSInternalInconsistencyException', reason: 'There are unexpected
subviews in the container view. Perhaps the embed segue has already
fired once or a subview was added programmatically?'.
Please see The attached image

If your UIViewController is not embedded with UINavigationController then you can not perform Push.
What you have to do is, embed-in navigation controller with your subVC and then push new view-controller from subVC and it will be in container view and will not take the full screen.
For your convenience, I attached the screenshot of the storyboard so you can get the better understanding. Hope it will help.

Related

ViewController Modal Presentation not appearing

I have a view controller that is a child view controller of my window's root view controller. That child view controller has a table view and when i select a row it tells the parent view controller to present a view controller modally. The modal view controller, however, never appears. I created a bare bones test view controller that just prints viewDidLoad and viewWillAppear. What I notice is that when I call parentVC.present(testVC, animated:true, completion:nil), viewDidLoad is run, but viewWillAppear is not. viewWillAppear is only then called when I interact with the UI in some way. Whether tapping, panning, scrolling or whatever.
I've spent hours trying to debug this. It doesn't seem like the main queue is blocked and I've reduced the problem to its bare bones. The modally presented view controller's viewWillAppear is simply not called until I interact with the UI again.
What could be causing this symptom?
In comments, you mention that you're instantiating your view controller with
let vc = TestVC()
where TestVC is presumably a (largely empty) UIViewController subclass.
A view controller needs a view created either via either storyboard scene (using instantiateViewController), a NIB or, in very rare cases, a view you create in loadView (which you shouldn’t be confused with viewDidLoad).
I’d suggest creating a storyboard scene (assuming you are using storyboards), give it a storyboard ID, and then use instantiateViewController:
let vc = storyboard.instantiateViewController(withIdentifier: "foo")
But just having a UIViewController subclass called TestVC and instantiating it with TestVC() won’t work.
In our discussion, you said you wanted to do this programmatically with no NIB nor storyboard. If so, use loadView. See https://stackoverflow.com/a/37964249/1271826 for an example.

How to get exact PresentingViewController when Modal View dismissed

My App navigation is like below:
NavigationController ---> RootViewController --(Show Segue)-> SomeViewController --(Show Segue)-> ParentViewController (With ContainerView)
So, ParentViewController has a container view.
This container view is populated programmatically, at runtime, depending upon user selection.
So, basically the view hierarchy is like this:
ParentViewController (With ContainerView) ---(Embed Segue) --> ContainerViewController --(Custom Segue, for deciding which child to show at runtime) --->
FirstChildViewController/SecondChildViewController
Now, I display a modal view when a button is tapped in SecondChildViewController. Everything is fine, till this point.
But, now I want to update data in SecondChildViewController on the dismissal of ModalViewController. I try to do it like this in ModalViewController:
SecondChildViewController *secondChildVC = (SecondChildViewController *)self.presentingViewController;
[self dismissViewControllerAnimated:YES completion: ^{ [secondChildVC updateList]; }];
But, I am getting following error:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[UINavigationController
updateList]: unrecognized selector sent to instance
0x127e451b0'
How can I fix this issue? So, to be specific, how can I get the "real" presentingViewController? I know its a bit weird navigation, and there is too much stacking on views from user experience point of view, but that is the way client wants to implement.
I am not sure if I understood your question correctly. If you have a ViewController A, presenting ViewController B, and if you wish to call a method in A when B is dismissed - you can make A a delegate of B.
Read more about Protocols and Delegates here:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html

Strange UINavigationController issue

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).

Link to another ViewController inside viewDidLoad method

in the viewDidLoad method i have this code.
When the application is running its not go to the another viewController, its gives me an error:
Warning: Attempt to present <CompleteCountryViewController: 0x7fb971779be0> on <ViewController: 0x7fb97176f3e0> whose view is not in the window hierarchy!
What can i do, that when the application running its will go to another viewController?
You should not present a view controller in the viewDidLoad method of another controller because you cannot show a view controller (present modally or push) when a transition is already occurring (push, pop, present, dismiss).
My suggestion is that you move the code in your code sample to the viewDidAppear: method. At this point, you know for sure that the transition has completed.
You seem to have a slight misunderstanding of the lifecycle of UIViewController if you want to modally present a view controller inside the viewDidLoad of another one.
viewDidLoad gets called in one view controller after it has been instantiated and its view components have been loaded (thus the name). The view of that view controller is about to be displayed, so it doesn't make much sense to instantiate another view controller at this point and present it on the first one.
Let me give you an example with two view controller A and B.
You instantiate A and its viewDidLoad gets called. So, A is about to be displayed! What you are doing in your code now is to instantiate B at this very point and show it on A. iOS doesn't like that and will give you your error.
I had an issue where I was attempting to present a modal view controller within the viewDidLoad method. The solution for me was to move this call to the viewDidAppear: method.
View controller's view is not in the window's view hierarchy at the point that it has been loaded (when the viewDidLoad message is sent), but it is in the window hierarchy after it has been presented (when the viewDidAppear: message is sent).

displaying a ViewController from a non UI class

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:).

Resources