How to initiate a viewcontroller without presenting it? - ios

I have a tab bar controller and a few other viewcontrollers outside the tab bar controller. I have this viewcontroller called "X" which is a part of the tab bar controller. I have another viewcontroller called "Y" which is not a part of the tab bar controller. Now i want to initiate X when im inside Y upon tapping a button without actually presenting it. I want X to become active and fire its viewdidload so that i can access X whenever i chose to do so. Is this possible. Im sorry if im not clear in explaining my quiestion. let me know if you need any other additional information.

Old question at this point, but I was looking for an answer myself just yesterday and managed to get it figured out.
Instantiate the ViewController, then call loadViewIfNeeded().
Example:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let exampleVC = storyboard.instantiateViewController(withIdentifier: "ExampleViewController") as! ExampleViewController
exampleVC.loadViewIfNeeded()
If you want, you can then check if the view is loaded with:
exampleVC.isViewLoaded
The ViewController is now all set up and ready for display when you decide to present it.

I want X to become active and fire its viewdidload so that i can access X whenever i chose to do so.
UIViewController uses lazy loading for the view property. You can just call:
[myViewController view];
This will trigger the loadView and/or viewDidLoad methods, if implemented.
However, you may wish to consider moving the relevant logic from viewDidLoad to init (or initWithCoder: if using a storyboard/xib). This way you won't have to call -view.

If I understand right, you want X to be initialised. So you can perform all you initialisation actions on your init constructor. viewDidLoad will only be called by the framework when you perform some presentation, either by pushViewController or addSubview. The reason for that is that because the framework wants to avoid getting instances of views on the memory without being used. So you can initialise all you want from your controllers but the views won't be loaded.

Related

How to access previous view controller from a dismiss command

Throughout my app I use a navigation controller to push and pop my view controllers. When I pop from one ViewController, I check to see if I can reload the data in the previous one with this:
_ = self.navigationController?.popViewController(animated: true)
if let previousViewController = self.navigationController?.viewControllers.last as? AnimalsVC {
previousViewController.tableView.reloadData()
}
This works every time, but now I need to do the same with another view, but it's not apart of the navigation controller because I modally present (instead of pushing it to the navigation controller). Now there's no way I can access the previous ViewController like before and I can not figure out how to access the previous ViewController.
How can I access the previous ViewController to reload the tableview like the example code without accessing the navigation controller?
I know this is possible with notifications, but I prefer not to use that method if possible!
First of all, It's not necessary to access the previous ViewController to reload tableview(or any other func)
I recommend you to use Delegate to achieve the same feature.
Holding a reference to the previous viewController in the way you mentioned will make your app very hard to maintain when your app gets more complicated.
You can call tableview.reloadData() in viewWillAppear method in the controller that you present modally

Crash when trying to push view controller in Swift

I am having a weird issue where my app crashes when I am trying to push a new view controller. I have set up a swipe gesture and want to segue to another view controller when a swipe is detected. When I run these 2 lines of code ...
let viewController:ViewController = ViewController()
self.navigationController?.pushViewController(viewController, animated: true)
The app crashes not specifically on either of those lines of code but rather in my ViewController class when in my viewDidLoad method I run this piece of code...
imageView.layer.masksToBounds = true
If I comment that out it crashes when I set the auto-correction type of my textField. What am I doing wrong?
First place I look when the view immediately crashes is in the Outlets for that ViewController in InterfaceBuilder. I look for anything that shows up with an exclamation mark. That usually means I renamed an outlet or broke a connection somehow. Delete anything broken by pressing the little x by the item that's messed up. I'll attach a photo so you can see.
It seems you're loading a ViewController that exists in storyboard with
let viewController:ViewController = ViewController()
which will result in nil outlets , so you have to use
let viewController = storyboard.instantiateViewController(withIdentifier: "VCID") as! ViewController
and give that vc a storyboard identifier like VCID
I think I have solved the issue but it has a weird side effect. Instead of using the line of code in #Sh_Khan's answer, I used ...
let viewController = nav?.storyboard!.instantiateViewController(withIdentifier: "mainVC") as! ViewController
The variable nav is equal to the navigation controller of the current view-controller. This seems to work without any hiccups but for some reason the back button does not disappear from the navigation controller after the segue is preformed. Does anybody know a solution to this, if so leave a comment and I will update my answer.
EDIT:
Another issue is that it wipes everything changed on that ViewController by the user clear. Is there another way to instantiate a ViewController without clearing it?
Follow what #Sh_Khan has said and in addition to that make sure that the view that you are making the push segue from is embedded in a Navigation controller.

How can I show a banner UIView as part of the UINavigationController, when in some VC's vs others

Let's say we have a CustomNavigationController that subclass UINavigationController.
Let's use the following example to explain the question.
CustomNavC -> pushes on VC A. From VC A you can push on 2 different VC's. VC B and VC C. We'll say both these VC's push on various other VC's, further down the rabbit hole.
Now, let's say we want to show a UIView that acts as a banner view appearing directly underneath the navigation controller. However, we only want the banner to show on say VC A, VC C, VC E, VC J, etc.
Is there any possible way to do this from the CustomNavC itself? Or is the only way to gain this control of which VC's show the banner... is to put it on the VC's itself?
1) We put it on the CustomNavC view. When the user moves from a VC to a VC that both show the banner (A->C), we want to same banner to remain. We gain this by laying out the banner on the CustomNavC. However, how can we check whether a VC should be displaying the banner or not? Every time the NavC pushes or pops a VC, we would have to check. Likely some function on each VC like -(BOOL)allowBannerViewDisplay and VC's can opt in.
2) If we put the BannerView on individual VC's, it becomes a bit easier but the deal breaker is that if we move from VC A -> VC C, the user is going to see 2 separate banners during the transition instead of the same banner.
So, we need to solve it way 1. The CustomNavC listens for a notification and displays the banner. It would then need to check the currently displaying VC and only display the banner if the VC allowed it. However, if the user transitions to another VC, it needs to recheck the logic of whether the banner is currently displaying and if it is, check if that VC wants it to display.
All of this feels weird to me.
Suggestions?
I've never implemented something like this, but off the bat my thought is this:
Set up this custom view as a new class, and pass the reference along your VCs. Set up a method on the custom View as a class method that takes in a UIViewController and returns a bool for whether or not it should be displayed (rather than on each of your VCs). This class method can get the class and see if it exists in an array of class names or something.
Now, I've never moved a UIView from one VC to another, but I think it's possible to remove the UIView as a subview from the VC it's on, and place it on the new one as a subview.
Alternatively, perhaps you could have a datasource/delegate object for this custom view, and create a new custom UIView on each VC as needed that all reference the same datasource / delegate to set up the state appropriately.

viewDidLoad vs ViewWillAppear in IOS

Please help me with this. I have created a simple project with two views as shown. I have attached the images for my storyboard and swift files. So, I read that viewdidload will be executed only once while loading the view into the memory. But, when I make a transition from secondview to the firstview the viewdidload is executing again and so is the print statement in the viewdidload method.
Someone please explain me this.
viewDidLoad is not called once for the Application. It is get called once for that viewController when the view holds memory and loaded.
So as many number of of time you push to the viewController, that many times it will call the viewDidLoad
viewDidLoad() — Called when the view controller’s content view (the top
of its view hierarchy) is created and loaded
viewWillAppear() — Intended for any operations that you want always to
occur before the view becomes visible.
For more info about this look at the link : https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson4.html
So if the view is already in memory (Like your case), then no need to push again, only need to pop back by this code
self.navigationController?.popViewControllerAnimated(true)
You should not make transition from secondViewController to firstViewController for back. Pop the second view controller by this code to back:
self.navigationController?.popViewControllerAnimated(true)
When you make a transition it makes a new instance from your firstViewController but when you pop the second view controller it dismiss your secondViewController and shows your last viewed viewController again.
Or
in the case that you are not using navigationController you should use below code to dismiss your secondViewController
self.dismissViewControllerAnimated(true, completion: {});
The main point is that you should not use new transition for back.
The simplest way:
1.First embed your ViewController in NavigationController
2.Call to this (instead of create segue for backing)
navigationController?.popToRootViewController(animated: true)
viewDidLoad will be called only once

Objective-c Conditionally serve ViewControllers after app launches

I have a question about loading view controllers when an app launches. I want to have a condition that checks when the application launches based upon stored core data values and if true, it will load the view controller second in the stack. If false, I want to load the root view controller. I want to always preserve the root view controller not matter what the result of the condition, I just want to skip loading this view if the result of my condition is true and go right to the second view in the stack. I am not using storyboards. Has anyone done anything of this nature before?
Now, having said that, is this logic flow an acceptable solution to be implementing. Will there be issues during submission if I try something like this?
Let's say you have the following view controllers:
UINavigationController *navigationController;
UIViewController *firstViewController;
UIViewController *secondViewController;
Then you can write code like this (edit: reworked solution based on comments below):
if (yourCondition)
navigationController.viewControllers = #[ firstViewController, secondViewController ];
else
navigationController.viewControllers = #[ secondViewController, firstViewController ];
Early in your app's launch, like in -applicationDidFinishLaunchingWithOptions:, check the condition in question and, if true, push the second controller onto the navigation stack. Specify NO for the animation parameter so that there's no obvious transition.
You can also set the nav controller's viewControllers property directly. Set it to an array with first and second controllers if the condition is true, or just the first controller otherwise.
Check the conditions in the -applicationDidFinishLaunchingWithOptions: is the simple way.
However, we are suppose to keep the AppDelegate away from complicated. The best way to do the launching things, like check some condition, prepare the data, is to create a LaunchViewController as the rootViewController, you can make it the same looking as your app launch image. Then, you can presenting any VC you want with/without animation, it will be the first VC that user will see.
Let me know if you need more help.

Resources