pushViewController not working read much online though - ios

Here is what code I get online, and it does work on previous project that I develop.But in this project, self.navigationController is null when I NSLog it, and guys online talked about add some code in delegate file, but I found nothing in previous project also I am not very clear what code should I add there. Anyone can give me a hand?
UIViewController *next = [[self storyboard] instantiateViewControllerWithIdentifier:#"ViewCollection"];
[self.navigationController pushViewController:next animated:YES];

If UINavigationController is nil, it means that the view controller that you use (which you instantiate from a Storyboard) is not actually embedded within a UINavigationController.
In order to embed it into a UINavigationController, you need to drag and drop a UINavigationController into your Storyboard and then ctrl-drag from the UINavigationController to your custom view controller and set it as the rootViewcontroller of the UINavigationController.

as nburk said: you need a NavigationController with a RootViewController which is your view. and dont forget to set the NavigationController as Initial View Controller. This all is done in the IB.

Related

Can't push viewController because navigationController is nil

I can't perform a transition between viewControllers because navigationController is nil. I have logged navigationController in different parts of the class but it returns nil everywhere. In storyboard the viewController is embedded in a navigationController. I have checked other threads on SO with the same issue, but none of the answer has helped or even really made sense to me.
Can't push because self.navigationController is nil
navigationController is nil,when push the viewcontroller
Why is it nil? And how do I solve this? An error message is also returned:
I have tried both using a segue:
[self.navigationController performSegueWithIdentifier:#"experienceDetails" sender:self];
as well as pushing:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Inspiration" bundle:nil];
ExperienceViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"experience"];
[self.navigationController pushViewController:viewController animated:NO];
Nothing happens using push but an error message is produced:
Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior
I have looked for solutions on that error too, but there doesn't seem to be a clear and concrete answer to how to solve it. Again, those suggestions I read and tried didn't work.
I'm really at a loss here. Such a simple thing to do but I'm hindered by something I don't even understand.
EDIT
If it helps, I have a tab bar and in one item I have the viewController that is embedded in a navigationController and from there I want to push to another viewController within the same storyboard.
EDIT
I got this to work:
[self showViewController:viewController sender:self];
very likely because it doesn't use navigationController. Its presented as modular though and is not part of the navigation stack, which is not something I want. Just good to know that things would work if navigationController wasn't nil.
I reproduced the described behaviour when segue experienceDetails was created from navigation controller... and here is solution
1) deleted segue experienceDetails form navigation controller
2) created push segue with identifier experienceDetails from included view controller to detail view controller
3) in view controller performed segue from self as below
[self performSegueWithIdentifier:#"experienceDetails" sender:self];

access multiple viewControllers from the main viewControllers programmatically in a storyboard

first part of my question is basic understanding.
I believe the other viewControllers in the storyboard are in a "Non instantiated" form when application is launched, and are launched when they are sequed, please confirm?
Second part how do I programmatically instantiate a sibling UIViewController within the storyboard and optionally create a seque to it. I've found some code from Objective-C (pasting below) but looking for a solution in SWIFT.
MyViewController *myVC = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"MyViewController"];
Your first statement is true to a certain extent. Any controller connected to one that does get instantiated by a relationship segue or an embed segue will also be instantiated (like all the children of a tab bar controller). In your code snippet, you don't need to use storyboardWithName: if you're calling that method from a controller that was created in the same storyboard; you can just use self.storyboard.
var myVC = self.storyboard.instantiateViewControllerWithIdentifier("MyViewController")

ContainerView childViewControlllers view frame taking whole screen

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.

Which is the recommended way to segue from one view controller to another?

I like to segue from the current view controller to the "settings" view controller. Which method is more efficient to transition and why? Thanks! I have to segue in code because I have to observe a condition at run time.
Method 1:
UINavigationController *navigationController = (UINavigationController *)[[[UIApplication sharedApplication] delegate] window].rootViewController;
SettingsViewController *v = [self.storyboard instantiateViewControllerWithIdentifier:#"settings"];
[navigationController pushViewController:v animated:YES];
Method 2: In the storyboard, control-drag the current view controller icon (bottom left) to "settings" view controller and then name the segue identifier "gotoSettingsVC", set style to "push" and then use this code...
[self performSegueWithIdentifier:#"gotoSettingsVC" sender:nil];
Both work just fine.
If you're using storyboards, segues are probably the better way to go. Instantiate the initial view controller and let the segues be your guide.
Also, while Method 1 can be used with storyboards, unlike segues, it also can be used with regular xibs (or no interface builder at all) as well.
Other than that, it comes down to preference. Some people hate the interface builder and others swear by it. ;)

Contained UIViewControllers - should I use .xib or the storyboard?

I'm making an app that will have a VC doing a similar job as a UITabBarController and I'm using
[self addChildViewController:theViewController];
// [self addSubview ... etc
to put a custom UIViewController's view as a subview of my main (root) VC.
So my question is, which is the correct way to instantiate a VC and not have to build it's UI programatically - from a .xib file, or from a storyboard?
With a xib:
UICustomViewController *controller = [[UICustomViewController alloc] initWithNibName:#"customVC" bundle:nil];
With a storyboard:
UICustomViewController* child = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
I believe .xib files are old stuff and storyboards are the way to go, but I also read this article, which suggests that using a storyboard to do this is a bit hacky. I don't know, any thoughts?
there is nothing any major difference in both way , they are same . but in many other angle storyboard is the straight way, there is nothing any hacky
If you want the child view controller to be present when the app opens, you can do it in a storyboard without any code at all. Add a container view to your root vc, and you will automatically get a view controller embedded in it.

Resources