Load multiple viewcontrollers on app init - ios

I'm trying to load 2 view controllers at the same time after the launchscreen.
Here's the stack I want to do:
SECOND VC - Currently being viewed
FIRST VC
Root VC
I did a workaround on it by calling presentViewController method under the viewDidAppear, but the result is the root vc is visible for a half second then the FIRST VC loads then finally loads the SECOND VC last.
The idea here is to have SECOND VC to be seen first then once dismissed it will slide down and shows the FIRST VC then hides to the ROOT VC last.
what methods should I use to accomplish this?
EDIT: Here's the example:
ROOT VC
override func viewDidAppear(animated: Bool){
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let firstVC: firstViewController = storyboard.instantiateViewControllerWithIdentifier("firstVC") as! firstViewController
self.presentViewController(firstVC, animated: false, completion: nil)
}
FIRST VC
override func viewDidAppear(animated: Bool){
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let secondVC: secondViewController = storyboard.instantiateViewControllerWithIdentifier("secondVC") as! secondViewController
self.presentViewController(secondVC, animated: false, completion: nil)
}
Then I would have a button on the SECOND VC and FIRST VC to dismiss it

Related

Moving back to parent view controller or dismissing child view controller

On click of a button, I am navigating from one controller to another. I was initially doing self.present(nextViewController, animated:true, completion:nil) and it was covering the whole window on the device. Since I wanted it to be of the size of my main (presenting) controller, below is the code that I use now to present new controller.
Navigating to NewViewController from Parent Controller:
#IBAction func doneButtonAction(_ sender: Any) {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "MyViewID") as! NewViewController
nextViewController.view.frame = self.view.bounds
nextViewController.willMove(toParent: self)
self.view.addSubview(nextViewController.view)
self.addChild(nextViewController)
nextViewController.didMove(toParent: self)
//self.present(nextViewController, animated:true, completion:nil)
}
This works fine and navigates me to NewViewController controller. But now from NewViewController controller, I wish to come back to this parent controller for which my dismiss logic is not working.
Going back from NewViewController to Parent Controller
#IBAction func backButtonAction(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
What am I missing? How do I go back to the parent controller?
What you actually had to do to present over the entire window was to modify modalPresentationStyle property of nextViewController.
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "MyViewID") as! NewViewController
nextViewController.modalPresentationStyle = .fullScreen
present(nextViewController, animated: true)
Add this code to doneButtonAction and present it the old way.

Attempt to present UIImagePickerController on ViewController whose view is not in the window hierarchy

I'm in trouble, after that I'm moving from View Controller to a second View Controller and then switching back to the View Controller and clicking on the UI Image Picker it's not appearing and bringing me back to the second View Controller. On the debugger it's appearing:
Attempt to present on whose view is not in the window hierarchy!
I'm really becoming crazy. My code that is bringing me back from second View Controller to the first View Controller is inside a button and it's below:
#IBAction func profileButton(_ sender: Any) {
let webVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController") as! ViewController
webVC.profileLink = linkProfilo
self.present(webVC, animated: false, completion: nil)
}
in second view controller add this variable:
var firstVC: ViewController?
and this setter function to set it
setup(firstVC: ViewController) {
self.firstVC = firstVC
}
in the first view controller, when presenting second view controller pass in a reference to self (first view controller)by calling the setup function
let secondVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondViewController") as! ViewController
secondVC.setup(firstVC: self)
self.present(secondVC, animated: false, completion: nil)
now when button is clicked in secondVC,
guard let first = self.firstVC else {return}
first.profileLink = linkProfilo
self.dismiss(animated: false, completion: nil)
I finally found the way for fix all of this:
#IBAction func profileButton(_ sender: Any) {
if let webVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController") as? ViewController {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
webVC.profileLink = linkProfilo
dismiss(animated: false, completion: nil)
appDelegate.window?.rootViewController!.present(webVC, animated: false, completion: nil)
}
}
it's enough to add the appDelegate sharing method and dismiss before to present the webVC for share the data in the right way and don't cause problems on the first view when presented.

Load all views related to tab bar controller by hard code

I would like to jump from a viewController to the first viewController related to Tab Bar Controller through code.
The tabBarController Scene has storyboard id tabView.
I'm working on this way:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc: UITabBarController!
storyboard.instantiateViewController(withIdentifier: "tabView")
vc=storyboard.instantiateViewController(withIdentifier: "tabView") as! UITabBarController
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.present(vc as! UIViewController, animated: true, completion: nil)
}
But it loads only the first viewController (out of 5) without the tab bar related to. How can I solve it?
Oh, this code looks so wrong.
In your storyboard give and "tabView" ID to the TabBarController, not the ViewController inside it.
Why you are double instantiating ViewController? just do it once and assign it to the vc variable.
Why you've created delay before presenting the VC? It's some sort of workaround of something?
Working code:
let vc = storyboard.instantiateViewController(withIdentifier: "tabView") as! UITabBarController
self.present(vc, animated: true)
Use
(1)if you want to navigate from Appdelegate
let appDelegate = UIApplication.sharedApplication.delegate as! AppDelegate
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let tabBar = mainStoryboard.instantiateViewControllerWithIdentifier("TabBarController") as! TabBarController
appDelegate.window?.rootViewController = tabBar
appDelegate.window?.makeKeyAndVisible()
(2)if you want to navigate from viewcontroller which has root of navigation
self.navigationController?.pushViewController(tabBar, animated: true)

How to call another Storyboard as a popover?

Assumed there is a 'ViewControllerOne' in Storyboard 'A'. If a user tapped a button on it, 'ViewControllerOne' will call Storyboard 'B' and show it as a popover on the screen. It seems that I can't find any references for my problem.
I would like to call another Storyboard from a Storyboard and show it as a popover, is it possible to do this? Thank you.
EDIT
I've tried the solution provided by #Sohil R. Memon, but I got an error :
reason: 'Storyboard (<UIStoryboard: 0x7fe69a841f00>) doesn't contain a view controller with identifier 'PaymentOnly''
I've added the RestorationID to the View Controller.
But if I change the code to :
let storyBoard : UIStoryboard = UIStoryboard(name: "PaymentOnly", bundle:nil)
let navigationController: UINavigationController = storyBoard.instantiateInitialViewController() as! UINavigationController
let viewController = navigationController.viewControllers[0] as! PaymentOnlyViewController
self.navigationController?.pushViewController(viewController, animated: true)
It worked but doesn't pop over the view. Below is the code from #Sohil R. Memon :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "PaymentOption" {
let storyBoard = UIStoryboard(name: "PaymentOnly", bundle: nil)
let vc = self.storyboard!.instantiateViewControllerWithIdentifier("PaymentOnly") as! PaymentOnlyViewController
self.presentViewController(vc, animated: false, completion: nil)
}
}
You can obviously present / popover any of the UIViewController from anywhere in any UIStoryBoard.
Expecting this is your first UIViewController and you want to call any other UIViewController from other UIStoryBoard. So for that find the below code:
let storyBoard = UIStoryboard(name: "storyboard_name", bundle: nil)
let vc = self.storyboard!.instantiateViewControllerWithIdentifier("chatVC") as! ChatVC
self.presentViewController(vc, animated: false, completion: nil)
This way you can present or push any of the UIViewController.
Popover reference link.

Go to a nested ViewController from a main TabBarController programmatically in Swift

I have the following ViewController structure, see image below.
Whenever I want to move from ViewController 1 to any of the other main controllers I use self.tabBarController?.selectedIndex = indexNumber
// for instance, this would take me to ViewController 3
self.tabBarController?.selectedIndex = 2
Based on the picture below, how can I go from ViewController 1 to TargetViewController programmatically when a button is tapped in ViewController 1?
FYI -
In the picture below I'm showing a button in ViewController 3 this is just to show the storyboard structure, the actual button-tap will happen in ViewController 1
EDIT:
Here is how you do it based on Prashant Tukadiya's answer.
ViewController 1
In ViewController 1 add the following in your tap event.
self.tabBarController?.selectedIndex = 2
let nav = (self.tabBarController?.viewControllers?[2] as? UINavigationController)
let vc = TargetViewController.viewController()
nav?.pushViewController(vc, animated: true)
TargetViewController
In your TargetViewController add the following class method.
class func viewController() -> TargetViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
return storyboard.instantiateViewController(withIdentifier: "targetViewControllerID") as! TargetViewController
}
Add targetViewControllerID in the Storyboard ID field.
I was facing same before a couple of days and finally, I got a solution maybe this will help you.
TabController.shared.tabcontroller.selectedIndex = 1
let navigation = TabController.shared.tabcontroller.selectedViewController?.navigationController
let SavedAddress = self.storyboard?.instantiateViewController(withIdentifier: "SavedAddressVC") as! SavedAddressVC
navigation?.pushViewController(SavedAddress, animated: true)
I have used the same solution. and this is the working code for me.
You can directly give identifier to the TargetViewController from storyboard and load from storyboard then and push or present it.
like add this method in your TargetViewController
class func viewController () -> TargetViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
return storyboard.instantiateViewController(withIdentifier: "yourIdentifer") as! TargetViewController
}
and on tap event
let vc = TargetViewController.viewController()
self.navigationController?.pushViewController(vc, animated: true)
EDIT
After reading comments got clear idea about your requirements
On button action from ViewController1, You want to goto TargetViewController but when press back you want back to viewController 3
Select particular index first
self.tabBarController?.selectedIndex = 2
After that you need to grab UINavigationController
let nav = (self.tabBarController?.viewControllers?[2] as? UINavigationController)
then Push ViewController
let vc = TargetViewController.viewController()
nav?.pushViewController(vc, animated: true)
Note: Don't forgot add identifier to storyboard to TargetViewController and also add class func viewController () -> TargetViewController method to TargetViewController
Hope it is helpful
In action function of a button in ViewController 1 , you can use this :
func presentMethod(storyBoardName: String, storyBoardID: String) {
let storyBoard: UIStoryboard = UIStoryboard(name: storyBoardName, bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: storyBoardID)
self.definesPresentationContext = true
self.present(newViewController, animated: true, completion: nil)
}
//usage
presentMethod(storyBoardName: "Main", storyBoardID: "TargetViewController")

Resources